Aims and content

The present document includes the R code to be used for implementing the data pre-processing steps required or recommended to prepare intensive longitudinal design (ILD) datasets for being analyzed with multilevel and other data analysis techniques. After a few setting procedures, the document depicts each step based on simple and commented R code ranging from data reading to data merging, cleaning, and centering, up to psychometric analyses and computation of the composite scores. Then, the document include a few examples of descriptive and inferential multilevel analyses that can be applied to investigate the job demand-control hypotheses (Karasek, 1979) from the pre-processed dataset. Finally, the document ends with an illustration of how a multiverse data manipulation approach can be applied to evaluate the robustness of the obtained findings.

The document and the included code are based on R 4.4.1, as returned by the R.version command below. To get start with R, we recommend Kabacoff (2022), Einspruch (2022), and Wickham et al. (2023) (freely available at this link). Specifically for I/O psychologists, we also suggest three books on human resources analytics in R: Caughlin (2023) (freely available at this link), McNulty (2022) (freely available at this link), and Starbuck (2023) (freely available at this link).

R.version
##                _                                
## platform       x86_64-w64-mingw32               
## arch           x86_64                           
## os             mingw32                          
## crt            ucrt                             
## system         x86_64, mingw32                  
## status                                          
## major          4                                
## minor          4.1                              
## year           2024                             
## month          06                               
## day            14                               
## svn rev        86737                            
## language       R                                
## version.string R version 4.4.1 (2024-06-14 ucrt)
## nickname       Race for Your Life

Note that any text preceded by the # symbol is a comment that is not considered by R.

# this is a comment

Here, we remove all objects from the R global environment to ensure that we start from scratch.

# removing all objets from the workspace
rm(list=ls())

The following R packages are used in this document (see References section):

# required packages
packages <- c("osfr","birk","plyr","psych","lavaan","lme4","sjPlot","ggplot2","gridExtra","tidyverse")
# run this line to install all missing packages
xfun::pkg_attach2(packages, message = FALSE); rm(list=ls())

Moreover, since we work with existing data available from the OSF repository at https://doi.org/10.17605/OSF.IO/87A9P, we use the osfr package to download the S5_processedData folder including the datasets. Note that the folder is downloaded in the current working directory used by R, which can be visualized by running the getwd() command.

# download dataset from OSF repository
library(osfr)
repo <- # retrieving repository
  osf_retrieve_node("https://doi.org/10.17605/OSF.IO/87A9P") 
osf_download(osf_ls_files(repo)[1, ], # downloading datasets into the current working directory
             conflicts="overwrite") 


1. Data manipulation steps

1.1. Data reading

First, we read the ild dataset including time-varying variables such as task demands and task control, and the preliminary questionnaire prelqs dataset including time-invariant variables such as participants’ age and gender. Both datasets were recorded using the CSV format and can be read with the read.csv() function. Note that we set stringsAsFactors = TRUE so that character string columns are considered as categorical variables.

# reading ILD dataset
ild <- read.csv("S5_processedData/ESM_processed.csv",
                stringsAsFactors = TRUE)

# reading preliminary questionnaire
prelqs <- read.csv("S5_processedData/RETRO_processed.csv", 
                   stringsAsFactors = TRUE) 
What if the data collection platform exports a separate file for each participant?
Click here to view additional code


In our case, we do not need to merge multiple data files because the dataset has already been unified (see full report). Yet, since some platforms export separate files grouping data by participant, it is worth illustrating how these can be merged into a single unified dataset. For doing this, we firstly split the ild dataset into separate data files that we save based on participant identifiers (i.e., participants ID are not reported in a dataset column but each file is named with the corresponding participant identifier). Then, we use the list.files function to list the names of, and the paths to, each data file. Second, we create an empty data.frame ild2 with zero row and the same number of column than the original ild dataset. Finally, we use a for-loop to read each data file, recreate the ID variable based on the file name, and add the new data to the empty dataset ild2 using the rbind function. We can see that the resulting dataset corresponds to the original ild dataset.

# saving data separately by participant after creating the "data-split" folder
dir.create("data-split") # creating the "data-split" folder inside the working directory
for(id in levels(as.factor(ild$ID))){ # saving data within the "data-split" folder
  write.csv(subset(ild[ild$ID==id,],select=-ID),paste0("data-split/",id,".csv"),
            row.names=FALSE) }
# note: the code above is just to illustrate this preliminary step
# selecting the name of the folder storing the data files
data.path <- "data-split"

# listing the file names within the data.path folder
fileNames <- list.files(data.path,full.names=TRUE)
fileNames # showing file names
##   [1] "data-split/S001.csv" "data-split/S002.csv" "data-split/S003.csv"
##   [4] "data-split/S004.csv" "data-split/S005.csv" "data-split/S006.csv"
##   [7] "data-split/S007.csv" "data-split/S008.csv" "data-split/S009.csv"
##  [10] "data-split/S010.csv" "data-split/S011.csv" "data-split/S012.csv"
##  [13] "data-split/S013.csv" "data-split/S014.csv" "data-split/S015.csv"
##  [16] "data-split/S016.csv" "data-split/S017.csv" "data-split/S018.csv"
##  [19] "data-split/S019.csv" "data-split/S020.csv" "data-split/S021.csv"
##  [22] "data-split/S022.csv" "data-split/S023.csv" "data-split/S024.csv"
##  [25] "data-split/S025.csv" "data-split/S026.csv" "data-split/S027.csv"
##  [28] "data-split/S028.csv" "data-split/S029.csv" "data-split/S030.csv"
##  [31] "data-split/S031.csv" "data-split/S032.csv" "data-split/S033.csv"
##  [34] "data-split/S034.csv" "data-split/S035.csv" "data-split/S036.csv"
##  [37] "data-split/S037.csv" "data-split/S038.csv" "data-split/S039.csv"
##  [40] "data-split/S040.csv" "data-split/S041.csv" "data-split/S042.csv"
##  [43] "data-split/S043.csv" "data-split/S044.csv" "data-split/S045.csv"
##  [46] "data-split/S046.csv" "data-split/S047.csv" "data-split/S048.csv"
##  [49] "data-split/S049.csv" "data-split/S050.csv" "data-split/S051.csv"
##  [52] "data-split/S052.csv" "data-split/S053.csv" "data-split/S054.csv"
##  [55] "data-split/S055.csv" "data-split/S056.csv" "data-split/S057.csv"
##  [58] "data-split/S058.csv" "data-split/S059.csv" "data-split/S060.csv"
##  [61] "data-split/S061.csv" "data-split/S062.csv" "data-split/S063.csv"
##  [64] "data-split/S064.csv" "data-split/S065.csv" "data-split/S066.csv"
##  [67] "data-split/S067.csv" "data-split/S068.csv" "data-split/S069.csv"
##  [70] "data-split/S070.csv" "data-split/S071.csv" "data-split/S072.csv"
##  [73] "data-split/S073.csv" "data-split/S074.csv" "data-split/S075.csv"
##  [76] "data-split/S076.csv" "data-split/S077.csv" "data-split/S078.csv"
##  [79] "data-split/S079.csv" "data-split/S080.csv" "data-split/S081.csv"
##  [82] "data-split/S082.csv" "data-split/S083.csv" "data-split/S084.csv"
##  [85] "data-split/S085.csv" "data-split/S086.csv" "data-split/S087.csv"
##  [88] "data-split/S088.csv" "data-split/S089.csv" "data-split/S090.csv"
##  [91] "data-split/S091.csv" "data-split/S092.csv" "data-split/S093.csv"
##  [94] "data-split/S094.csv" "data-split/S095.csv" "data-split/S096.csv"
##  [97] "data-split/S097.csv" "data-split/S098.csv" "data-split/S099.csv"
## [100] "data-split/S100.csv" "data-split/S101.csv" "data-split/S102.csv"
## [103] "data-split/S103.csv" "data-split/S104.csv" "data-split/S105.csv"
## [106] "data-split/S106.csv" "data-split/S107.csv" "data-split/S108.csv"
## [109] "data-split/S109.csv" "data-split/S110.csv" "data-split/S111.csv"
## [112] "data-split/S112.csv" "data-split/S113.csv" "data-split/S114.csv"
## [115] "data-split/S115.csv" "data-split/S116.csv" "data-split/S117.csv"
## [118] "data-split/S118.csv" "data-split/S119.csv" "data-split/S120.csv"
## [121] "data-split/S121.csv" "data-split/S122.csv" "data-split/S123.csv"
## [124] "data-split/S124.csv" "data-split/S125.csv" "data-split/S126.csv"
## [127] "data-split/S127.csv" "data-split/S128.csv" "data-split/S129.csv"
## [130] "data-split/S130.csv" "data-split/S131.csv" "data-split/S132.csv"
## [133] "data-split/S133.csv" "data-split/S134.csv" "data-split/S135.csv"
## [136] "data-split/S136.csv" "data-split/S137.csv" "data-split/S138.csv"
## [139] "data-split/S139.csv" "data-split/S140.csv" "data-split/S141.csv"
## [142] "data-split/S142.csv" "data-split/S143.csv" "data-split/S144.csv"
## [145] "data-split/S145.csv" "data-split/S146.csv" "data-split/S147.csv"
## [148] "data-split/S148.csv" "data-split/S149.csv" "data-split/S150.csv"
## [151] "data-split/S151.csv" "data-split/S152.csv" "data-split/S153.csv"
## [154] "data-split/S154.csv" "data-split/S155.csv" "data-split/S156.csv"
## [157] "data-split/S157.csv" "data-split/S158.csv" "data-split/S159.csv"
## [160] "data-split/S160.csv" "data-split/S161.csv" "data-split/S162.csv"
## [163] "data-split/S163.csv" "data-split/S164.csv" "data-split/S165.csv"
## [166] "data-split/S166.csv" "data-split/S167.csv" "data-split/S168.csv"
## [169] "data-split/S169.csv" "data-split/S170.csv" "data-split/S171.csv"
## [172] "data-split/S172.csv" "data-split/S173.csv" "data-split/S174.csv"
## [175] "data-split/S175.csv" "data-split/S176.csv" "data-split/S177.csv"
## [178] "data-split/S178.csv" "data-split/S179.csv" "data-split/S180.csv"
## [181] "data-split/S181.csv" "data-split/S182.csv" "data-split/S183.csv"
## [184] "data-split/S184.csv" "data-split/S185.csv" "data-split/S186.csv"
## [187] "data-split/S187.csv" "data-split/S188.csv" "data-split/S189.csv"
## [190] "data-split/S190.csv" "data-split/S191.csv" "data-split/S192.csv"
## [193] "data-split/S193.csv" "data-split/S194.csv" "data-split/S195.csv"
## [196] "data-split/S196.csv" "data-split/S197.csv" "data-split/S198.csv"
## [199] "data-split/S199.csv" "data-split/S200.csv" "data-split/S201.csv"
## [202] "data-split/S202.csv" "data-split/S203.csv" "data-split/S204.csv"
## [205] "data-split/S205.csv" "data-split/S206.csv" "data-split/S207.csv"
## [208] "data-split/S208.csv" "data-split/S209.csv" "data-split/S210.csv"
## [211] "data-split/S211.csv"
# creating empty data.frame ild2
ild2 <- data.frame(matrix(nrow=0,ncol=37))

# reading and merging data files into a unified dataset 'ild2'
for(fileName in fileNames){ # for each file included in the dat.path folder...
  newFile <- read.csv(fileName) # reading file
  newFile$ID <- gsub("data-split/","", # extracting participant ID from file name
                     gsub(".csv","",fileName))
  # adding new data to the empty data.frame (the row names should be the same)
  ild2 <- rbind(ild2,newFile) } 

# showing the unified dataset
ild2[,c("ID",colnames(ild2)[1:(ncol(ild)-1)])]
# showing the original dataset
ild

Then, we identify and select the main data columns of interest by using squared brackets [rownames, colnames] standing for ‘data subset’. Note that the names of the selected columns should be written within quotes (e.g., "ID") and should be included in the c() function, standing for ‘combine’. Of note, while the RunTimestamp and SubmissionTimestamp variables were named by the survey recording system, the remaining variables were carefully named to identify items belonging to the same scale (e.g., items starting with “d” were included in the Task Demand Scale, whereas items starting with “c” were included in the Task Control Scale). As highlighted in the main manuscript, strategically naming the variables is critical to prevent mistakes in the following steps and improve the effectiveness and transparency of the data analysis scripts.

# selecting columns of interest from ILD dataset
ild <- ild[,c("ID", # participant identifier
              "RunTimestamp","SubmissionTimestamp", # temporal coordinates
              "d1","d2","d3","d4", # task demands items
              "c1","c2","c3", # task control items
              "v1","v2","v3")] # negative valence items

# selecting columns of interest from preliminary questionnaire dataset
prelqs <- prelqs[,c("ID", # participant identifier
                    "age","gender")] # time-invariant variables

Finally, we take a first look at both datasets and the included number of participants and observations. We can see that both datasets include a total of 211 participants, with the ild dataset including a total of 2015 observations.

# ILD dataset
nrow(ild) # original number of observations
## [1] 2015
nlevels(ild$ID) # original number of participants
## [1] 211
head(ild) # showing first six rows of data
# preliminary questionnaire dataset
nrow(prelqs) # original number of observations and participants
## [1] 211
head(prelqs) # showing first six rows of data


1.2. Temporal synchronization

As a second step, we synchronize and verify the correctness of the temporal coordinates associated with each data point. In our case, temporal coordinates are only available for the ild dataset. We can verify their correctness by firstly converting them as POSIXct (i.e., the variable class used by R to work with dates and times), by splitting time and date information, and by checking whether response times are consistent with scheduled times. Note that the as.POSIXct function requires specifying the date-time format of the inputted character strings using the format argument. For instance, the date format “%Y-%m-%d” stands for dates expressed as “year-month-day”, reporting years with century (e.g., “2025”) and months and days as decimal numbers (e.g., “01” for January, and “02” for the second day of the month), whereas the time format “%H:%M:%S” stands for times expressed as “hours:minutes:seconds” as decimal numbers (for more details, run ?strptime in the console).

# response initiation and submission time as POSIXct
ild$RunTimestamp <- as.POSIXct(ild$RunTimestamp, 
                               format = "%Y-%m-%d %H:%M:%S")
ild$SubmissionTimestamp <- as.POSIXct(ild$SubmissionTimestamp, 
                                      format = "%Y-%m-%d %H:%M:%S")

# response initiation date as Date without time
ild$date <- as.Date(substr(ild$RunTimestamp,1,10),
                    format="%Y-%m-%d")

# response initiation time as POSIXct without date
ild$time <- as.POSIXct(substr(ild$RunTimestamp,12,19), 
                       format = "%H:%M:%S")

Here, we plot the histograms of the resulting date and time variables to verify the frequency of responses initiated inside and outside the study temporal frames. Note that with objects of class POSIXct the function hist (for plotting histograms) requires specifying the temporal intervals to be plotted with the argument breaks (for more details, run ?hist.POSIXt in the console), which we set to "months" and "hours" for response dates and times, respectively. We can see that response initiation dates and times are compatible with the data collection period (i.e., October 2018 - October 2019) and with the scheduled ESM timing (i.e., between 9:15 AM and 6:15 PM), respectively. A few cases (\(n\) = 22) are slightly outside the scheduled time intervals, but these might be due to variability in temporal synchronization across devices, so we keep them.

# plotting date and time
par(mfrow=c(2,1)) # this is to have 2 plots in the same panel 
hist(ild$date,breaks="months") # plotting date frequencies month-by-month
hist(ild$time,breaks="hours") # plotting time frequencies hour-by-hour

# number of cases with time outside the scheduled intervals
nrow(ild[!is.na(ild$time) & 
           (ild$time<as.POSIXct("09:15:00", format = "%H:%M:%S") | 
              ild$time>as.POSIXct("18:30:00", format = "%H:%M:%S")),])
## [1] 22

Moreover, we use the recoded temporal coordinates to create the variable day, indexing the day of participation from 1 to 3. This is done by using a for-loop that compares each row i in the ild dataset with the previous row i-1. Then, the if and else operators are used to establish the value of the day variables, such that it is increased by one unit every time that the value of the date variable increases by one day within the same participant, whereas it is reset to the value “1” every time that the value of the variable ID is different than the value reported in the previous row (i.e., day 1 for a different participant).

# creating day (i.e., day of participation from 1 to 3)
ild$day <- 1 # initially set as 1
for(i in 2:nrow(ild)){ # FOR each row starting from the second one...
  if(ild[i,"ID"] != ild[i-1,"ID"]){ # IF the ID value is different than the previous row...
    ild[i,"day"] <- 1 # ...restart from day 1.
    
  } else {  # IF the ID value is the same of the previous row...
    if(!is.na(ild[i,"date"]) & # AND both current and previous date are not missing...
       !is.na(ild[i-1,"date"]) & 
       as.POSIXlt(ild[i,"date"])$wday != # AND the date value is different than the previous row...
         as.POSIXlt(ild[i-1,"date"])$wday){
      ild[i,"day"] <- ild[i-1,"day"] + 1 # ...add 1 day.
      
    } else{ # IF same ID value but the date value is the same than the previous row...
        ild[i,"day"] <- ild[i-1,"day"] # ...keep the same day than the previous row.
        }}}

# sanity check: day can only take value 1, 2, or 3 (ok)
table(ild$day) 
## 
##   1   2   3 
## 753 647 615

Note that the day variable created above is only used to identify the observations associated with the same participant-by-day cluster, but it cannot be used to operationalize temporal distances as it does not imply equidistant intervals. Indeed, participants were allowed to freely choose whether starting on Monday, Wednesday, or Friday, implying that the distance between day 1 and day 2 can be equal to 2 days for some participants (i.e., from Monday to Wednesday or from Wednesday to Friday) and 3 days for some other participants (i.e., from Friday to Monday). To get a variable that indexes the day of the week by accounting for the actual temporal distance between days (i.e., implying equidistant intervals), it is possible to use the as.POSIXlt function by extracting the weekday with the $wday syntax. This returns the weekday number from 0 (Sunday) to 6 (Saturday). In our case, it can only get values 1 = Monday, 3 = Wednesday, or 5 = Friday.

data.frame(ID = ild$ID, # participant ID
           RunTimestamp = ild$RunTimestamp, # original date-time variable
           day = ild$day, # participant-by-day indicator created above
           wday = as.POSIXlt(ild$RunTimestamp)$wday) # day of week

Finally, we use the scheduled timestamps to create the variable beep, indexing the measurement occasion within each day, from 1 to 7. To account for potential variability in device temporal synchronization, 10 minutes are subtracted from each lower timestamp and added to each upper timestamp, respectively.

# listing minimum, central, and maximum scheduled time for each time point
times <- list(c("09:15:00","09:30:00","10:15:00"), # beep 1
              c("10:20:00","10:30:00","10:40:00"), # beep 2
              c("11:50:00","12:00:00","12:10:00"), # beep 3
              c("13:20:00","13:30:00","13:40:00"), # beep 4
              c("14:50:00","15:00:00","15:10:00"), # beep 5
              c("16:20:00","16:30:00","16:40:00"), # beep 6
              c("17:50:00","18:00:00","18:10:00")) # beep 7

# creating beep (i.e., survey number within day from 1 to 7)
for(i in 1:length(times)){ # assign beep value depending on each couple of min-max
  ild[!is.na(ild$time) & 
        ild$time > (as.POSIXct(times[[i]][1], format = "%H:%M:%S") - 10*60) & 
        ild$time < (as.POSIXct(times[[i]][3], format = "%H:%M:%S") + 10*60),"beep"] <- i }

# correcting beep when response time is outside the scheduled intervals
times <- c("09:30:00","10:30:00","12:00:00","13:30:00","15:00:00","16:30:00","18:00:00") # vector of central times
for(i in 1:nrow(ild)){ # when time is outside the scheduled intervals, the closest 'beep' value is assigned
  if(is.na(ild[i,"beep"]) & !is.na(ild[i,"time"])){ require(birk)
    ild[i,"beep"] <- which.closest(as.POSIXct(times, format = "%H:%M:%S"), ild[i,"time"]) }}
table(ild$beep) # sanity check: beep can only take value 1-7 (ok)
## 
##   1   2   3   4   5   6   7 
## 271 287 302 289 282 281 267

Here, we visualize the original RunTimestamp variable along with the newly created day and beep variables.

ild[,c("ID","RunTimestamp","day","beep")]


1.3. Data cleaning

Third, we inspect and filter cases of missing and inaccurate data. To track the total number of excluded observations and participants, we initially record the original sample size at both levels.

# original number of observations
n1 <- nrow(ild)

# original number of participants
n2 <- nlevels(ild$ID)

Even more wisely, we might save the original dataset(s) before applying any data cleaning procedure, so that if any error occurs in the process we can start from this ‘checkpoint’ rather than restarting from the beginning.

# saving data before cleaning it
ild.original <- ild
prelqs.original <- prelqs

# # run these lines to restart from the raw data
# ild <- ild.original
# prelqs <- prelqs.original


1.3.1. Incomplete responses

Here, we inspect and filer the number of cases with missing values for some or all variables (e.g., possibly due to lack of compliance or technical issues with the mobile app). First, we remove any participant that only responded to the preliminary questionnaire but did not respond to any ESM questionnaire (36, 1.8%), and vice versa (9, 4.3%). Note that the %in% operator is used to update each dataset by only including the ID values that are also included in the other dataset, and vice versa.

# removing participants with no response to the preliminary questionnaire
prelqs <- prelqs[!is.na(prelqs$age) & # only retaining rows with non-missing values to age...
                   !is.na(prelqs$gender),] # ... and gender
ild <- ild[ild$ID %in% as.character(prelqs$ID),] # updating ild dataset

# removing participants with no response to any ESM questionnaire
ild <- ild[!is.na(ild$RunTimestamp),] # only retaining rows with non-missing values to RunTimeSamp
prelqs <- prelqs[prelqs$ID %in% as.character(ild$ID),] # updating prelqs dataset

Then, we filter all responses to the first beep of each day (n = 260, 13.6%), which only included negative valence but not task demands or task control items.

# removing all responses to the first daily survey (not including task demands and task control)
N1 <- nrow(ild) # saving original sample size for comparison
ild <- ild[ild$beep!=1,] # removing responses to the first survey of each day
cat("Removed",N1-nrow(ild),"responses (",round(100*(N1-nrow(ild))/N1,1),"% )")
## Removed 260 responses ( 13.6 % )

Finally, we inspect and remove all cases with missing responses to any items (list-wise deletion). This is done by applying the na.omit function to the subset of the ild dataset that only includes the columns considered for the following steps, namely the participant identifier ID, the temporal coordinates of the responses, and the three multi-item scales. Specifically, items are selected with the paste0 function, which pastes the letter identifying each scale (i.e., v for negative valence, d for task demands, and c for task control) with the item number (e.g., paste0("v",1:3) returns a vector with values “v1”, “v2”, and “v3”).

# list-wise deletion: removing cases with missing responses to any core variable
N1 <- nrow(ild) # saving original sample size for comparison
ild <- 
  na.omit(ild[,c("ID", # participant identifier
                 "RunTimestamp","SubmissionTimestamp","day","beep", # temporal coordinates
                 paste0("v",1:3),paste0("d",1:4),paste0("c",1:3))]) # item scores
cat("Removed",N1-nrow(ild),"responses (",round(100*(N1-nrow(ild))/N1,1),"% )")
## Removed 71 responses ( 4.3 % )


1.3.2. Double responses

As a subsequent step, we inspect cases of double responses (i.e., two or more responses with the same ID, day, and beep values). Again, this is done with the paste0 function, which creates a variable combining participant, day, and beep identifiers so that we can identify and remove any cases of duplicated value for this variable. We can see that no duplicated cases are detected in our case.

# detecting double responses (i.e. same ID, day, and beep value)
nrow(ild[duplicated(paste0(ild$ID, ild$day, ild$beep)),]) # no double responses in the dataset
## [1] 0
# # run this line to remove double responses
# ild <- ild[!duplicated(paste0(ild$ID, ild$day, ild$beep)),]


1.3.3. Careless responses

Here, we inspect and filter cases of potentially careless responses and respondents. Specifically, following Curran (2016), we illustrate careless response detection by looking for cases with excessively fast response time. Considering the repetitive nature of ESM designs, we apply a more conservative criterion than that proposed by Curran (2016) (i.e., less than 2 seconds per item) and we remove all response taking 1.5 seconds per item. In our case, each ESM questionnaire included 21 items (see Menghini et al., 2023), resulting in a total cut-off time of 21 \(\times\) 1.5 seconds = 31.5 seconds. We can see that the time difference between SubmissionTimestamp and RunTimestamp values is lower than 31.5 seconds only in one case.

# detecting cases with total response time below 31.5 seconds
nrow(ild[difftime(ild$SubmissionTimestamp,ild$RunTimestamp,units="secs") < 31.5,])
## [1] 1
# removing cases with total response time below 31.5 seconds
ild <- ild[difftime(ild$SubmissionTimestamp,ild$RunTimestamp,units="secs") > 31.5,]


1.3.4. Compliance rate

Finally, we inspect the participants’ compliance rate and apply our exclusion criterion by removing all participants with less than 2 valid observations per day. First, we use a for-loop to compute the response rate of each participant (i.e., percentage of submitted responses over the 18 scheduled questionnaires for each participant) and, within that loop, we compute the total number of submitted responses for each participant-by-day couple, adding these variables to the prelqs dataset. Second, we plot the created response rate variables. Finally, we exclude participants with less than 2 responses per day.

# computing overall and daily compliance rate
for(i in 1:nrow(prelqs)){ # No. responses over total number of scheduled data points (n = 18)
  prelqs[i,"compRate"] <- 100*nrow(ild[ild$ID==as.character(prelqs[i,"ID"]),])/18
  for(day in 1:3){ # computing number of nonmissing data points per each day
    prelqs[i,paste0("n.day",day)] <- nrow(ild[ild$ID==as.character(prelqs[i,"ID"]) & ild$day==day,]) }}

# plotting original compliance
par(mfrow=c(1,4))
for(i in c("compRate","n.day1","n.day2","n.day3")){ hist(prelqs[,i],main=i) }

# excluding participants with less than 2 valid data points per day
N2 <- nrow(prelqs); N1 <- nrow(ild) # saving original sample sizes for comparison
prelqs <- prelqs[prelqs$n.day1 >= 2 & prelqs$n.day2 >= 2 & prelqs$n.day3 >= 2,] # excluding participants from prelqs
ild <- ild[ild$ID %in% as.character(prelqs$ID),]
cat("Removed",N2-nrow(prelqs),"participants (",round(100*(N2-nrow(prelqs))/N2,1),
    "% ) and",N1-nrow(ild),"observations (",round(100*(N1-nrow(ild))/N1,1),"% )")
## Removed 45 participants ( 27.1 % ) and 202 observations ( 12.8 % )
# plotting updated compliance
par(mfrow=c(1,4))
for(i in c("compRate","n.day1","n.day2","n.day3")){ hist(prelqs[,i],main=i) }


1.3.5. Excluded data

Here, we compute the total number of excluded observations and participants by comparing the original sample sizes with those obtained after applying all data cleaning procedures.

# resetting ID levels
ild$ID <- as.factor(as.character(ild$ID))
prelqs$ID <- as.factor(as.character(prelqs$ID))

# total number and percentage of excluded participants
n2 - nlevels(ild$ID); 100*(n2 - length(table(ild$ID)))/n2
## [1] 90
## [1] 42.65403
# total number and percentage of excluded observations
n1 - nrow(ild); 100*(n1 - nrow(ild))/n1
## [1] 637
## [1] 31.6129


1.4. Data merging

Here, we merge the time-invariant data included in the wide-form prelqs dataset (i.e., participants’ age and gender) with the time-varying data included in the long-form ild dataset. This is done with the join() function from the plyr package based on the shared variable ID, identifying all the data points associated with the same participant.

# data merging
library(plyr) # opening plyr package to use the join() function
ild <- join(ild, # long-form dataset
            prelqs[,c("ID","age","gender")], # selecting columns from the wide-form dataset
            by = "ID") # setting the column shared by the two datasets

# showing some columns from the merged dataset
ild[,c("ID","age","gender","day","beep","v1")]


1.5. Data centering

Here, we center any time-varying variable (i.e., ESM item scores such as v1) by computing the corresponding cluster-mean (e.g., v1_mean) and cluster-mean-centered variable (e.g., v1_cmc) (see see Hamaker & Grasman, 2015; Wang & Maxwell, 2015). Since in R the same result can be achieved in multiple ways, some of which might be more intuitive for some users but not for others, this step is implemented in two different ways, namely using base R and with the tidyverse syntax.

Base R

With base R, cluster means (named “variable_mean”) are computed using the aggregate function, which allows to compute the mean of one or more variables (here, the negative valence, task demand, and task control item scores) based on a grouping variable (here, the participant identifier variable ID). Then, we add cluster means to the ild long-form dataset and we use a for-loop for computing cluster-mean-centered scores (named “variable_cmc”) by subtracting cluster-mean values from the original variable values, for each time-varying variable.

# selecting variable names
VarNames <- c("v1","v2","v3","d1","d2","d3","d4","c1","c2","c3")

# computing cluster-mean values of time-varying variables
means <- aggregate(x = ild[,VarNames], # variables to be aggregated
                   by = list(ild$ID), # cluster variable (it should be a list)
                   FUN = mean) # aggregating function (mean)
colnames(means) <- c("ID", # renaming variables to avoid duplicated names below
                     paste0(VarNames,"_mean"))

# joining cluster means to the long-form dataset
ild <- plyr::join(ild,means,by="ID")

# computing cluster-mean-centered values
for(VarName in VarNames){ # for each time-varying variable
  ild[,paste0(VarName,"_cmc")] <- # the cluster-mean-centered variable (_cmc)...
    ild[,VarName] - # ...is equal to the original variable...
    ild[,paste0(VarName,"_mean")] } # ...minus the cluster-mean variable (_mean).

# showing example variables
ild[,c("ID","day","beep","c1","c1_mean","c1_cmc","d1","d1_mean","d1_cmc")]


Tidyverse

Here, we replicate the same operations in three alternative ways based on the tidyverse syntax (see Wickham et al., 2023). In option A, we use the pipe operator %>% to concatenate operations, the group_by function to group operations by participant ID, and the mutate function to specify which operations should be applied (i.e., computing cluster-mean and cluster-mean-centered values). In option B, we directly use the mutate function to specify both the operations to be applied and the grouping variable (specified with the argument .by). Finally, option C is an extension of option B where we use the across function to repeat the operations specified in the .fns argument across all the columns specified in the .cols argument of the mutate function. In this way, it is possible to avoid manually rewriting the same operations for each variable, as in option A and B.

# loading tidyverse package collection
library(tidyverse)

# option A: mutate and group_by
ild_tidyverse_A <- 
  ild %>%
  group_by(ID) %>% # grouping operations by cluster variable "ID"
  mutate(c1_mean = mean(c1), # computing cluster-mean variables (only examples)
         d1_mean = mean(d1),
         c1_cmc = c1 - c1_mean, # computing cluster-mean-centered variable (only examples)
         d1_cmc = d1 - d1_mean) 
ild_tidyverse_A[,c("ID","day","beep","c1","c1_mean","c1_cmc","d1","d1_mean","d1_cmc")]
# option B: mutate with ".by"
ild_tidyverse_B <- 
  mutate(ild,
         c1_mean = mean(c1), # computing cluster-mean variables (only examples)
         d1_mean = mean(d1),
         c1_cmc = c1 - c1_mean, # computing cluster-mean-centered variable (only examples)
         d1_cmc = d1 - d1_mean,
         .by = ID) # grouping operations by cluster variable "ID"
ild_tidyverse_B[,c("ID","day","beep","c1","c1_mean","c1_cmc","d1","d1_mean","d1_cmc")]
# option C: repeat option B over multiple columns using the "across" command
ild_tidyverse_C <-
  mutate(ild,
         across(
           # selecting all the columns on which repeating the operations
           .cols = c("v1","v2","v3","d1","d2","d3","d4","c1","c2","c3"), 
           .fns = list( # list of operations to be repeated
             mean =~ mean(.x), # computing cluster-mean variable
             cmc =~ .x - mean(.x) )), # computing cluster-mean-centered variable
         .by = ID) # grouping operations by cluster variable "ID"
ild_tidyverse_C[,c("ID","day","beep","c1","c1_mean","c1_cmc","d1","d1_mean","d1_cmc")]


1.6. Psychometrics

Here, we evaluate the psychometric properties of the considered ESM variables.

1.6.1. Item scores

First, we visualize the distribution of, and the correlations between, item scores. We can see that all item scores share the same range (1-7) and that most scores are quite symmetrically distributed, although with some skewed distributions (items c1, c2, and c3). Better symmetry is shown by cluster-mean and cluster-mean-centered values.

# selecting items to be evaluated
items <- c("v1","v2","v3","d1","d2","d3","d4","c1","c2","c3")

# plotting original item score distributions
par(mfrow=c(2,5))
for(item in items){ hist(ild[,item],main=item,xlab="",breaks=30) }

# plotting cluster-mean score distributions
par(mfrow=c(2,5))
for(item in items){ hist(ild[!duplicated(ild$ID),paste0(item,"_mean")],main=paste0(item,"_mean"),xlab="",breaks=30) }

# plotting cluster-mean-centered score distributions
par(mfrow=c(2,5))
for(item in items){ hist(ild[,paste0(item,"_cmc")],main=paste0(item,"_cmc"),xlab="",breaks=30) }

Here, we compute and visualize the level-specific zero-order correlations among the considered items. Level-1 (within-individual) and level-2 (between-individual) correlations are computed by correlating cluster-mean-centered (n = 1378) and cluster-mean values (n = 121), respectively. We can see that correlations are in the expected directions, with stronger correlations at level 2 (shown below the main diagonal) than at level 1 (shown above the main diagonal), and among item scores belonging to the same scale than among scores from different scales.

# computing level-1 correlations
cor1 <- round(cor(ild[,items]),2)

# computing level-2 correlations
cor2 <- round(cor(ild[!duplicated(ild$ID),paste0(items,"_mean")]),2)

# visualizing correlations
library(psych)
cor1[lower.tri(cor1)] <- cor2[lower.tri(cor2)] # merging the two matrices
corPlot(cor1) # plotting correlation matrix


1.6.2. Reliability indices

Here, we compute reliability indices based on generalizability theory, that is by fitting a random-intercept-only model to decompose the variance in item scores based on participants, items, time, and their interactions (see Shrout & Lane (2012); Cranford et al., 2006). This is done using the multilevel.reliability() function from the psych package.

# isolating focused items
items <- c("v1","v2","v3")

# creating variable 'time' (joining day and beep)
ild$time <- paste(ild$day, ild$beep)

# computing reliability indices for negative valence items
multilevel.reliability(x = ild, # long-form dataset
                       grp = "ID", # cluster variable (categorical)
                       Time = "time", # time variable (categorical)
                       items = items, # item names
                       lmer = TRUE, aov = FALSE # additional arguments to be included
                       )[c("RkF", "Rc")] # selecting the target coefficients
## $RkF
## [1] 0.982208
## 
## $Rc
## [1] 0.711622
# reliability indices for task demands
multilevel.reliability(ild, grp="ID", Time="time", items=c("d1","d2","d3","d4"),lmer=TRUE, aov=FALSE)[c("RkF","Rc")]
## $RkF
## [1] 0.9873327
## 
## $Rc
## [1] 0.8243137
# reliability indices for task control
multilevel.reliability(ild, grp="ID", Time="time", items=c("c1","c2","c3"),lmer=TRUE, aov=FALSE)[c("RkF","Rc")]
## $RkF
## [1] 0.9799259
## 
## $Rc
## [1] 0.7392937


1.6.3. MCFA

Here, we provide some illustrative code exemplifying a way to conduct a multilevel confirmatory factor analysis (MCFA) of the considered items, based on Jack & Jorgensen (2017). Specifically, we fit and compare a configural model fit.conf (with the same factor structure across levels) and a weak-invariance model fit.winv (with both the same structure and equivalent factor loadings across levels). We can see that the two models fit the data comparably, and we trust the weak-invariance model fit.winv.

# model specification: configural model (same structure across levels)
m.conf <- 'level: 1
           NegVal_w =~ v1 + v2 + v3
           taskDem_w =~ d1 + d2 + d3 + d4
           taskCon_w =~ c1 + c2 + c3
           
           level: 2
           NegVal_b =~ v1 + v2 + v3
           taskDem_b =~ d1 + d2 + d3 + d4
           taskCon_b =~ c1 + c2 + c3'

# model specification: weak-invariance model (same structure and loadings across levels)
m.winv <- 'level: 1
           NegVal_w =~ a*v1 + b*v2 + c*v3
           taskDem_w =~ d*d1 + e*d2 + f*d3 + g*d4
           taskCon_w =~ h*c1 + i*c2 + j*c3
           
           level: 2
           NegVal_b =~ a*v1 + b*v2 + c*v3
           taskDem_b =~ d*d1 + e*d2 + f*d3 + g*d4
           taskCon_b =~ h*c1 + i*c2 + j*c3
           '

# model fit (note: some participants show no variance in some items, which is quite common)
library(lavaan)
fit.conf <- cfa(model = m.conf, data = ild, cluster="ID", std.lv=TRUE)
fit.winv <- cfa(model = m.winv, data = ild, cluster="ID", std.lv=TRUE)

# fit indices
round(lavInspect(fit.conf, what = "fit")[c("rmsea","cfi","srmr_within","srmr_between")],3) # configural
##        rmsea          cfi  srmr_within srmr_between 
##        0.033        0.979        0.031        0.059
round(lavInspect(fit.winv, what = "fit")[c("rmsea","cfi","srmr_within","srmr_between")],3) # weak invariance
##        rmsea          cfi  srmr_within srmr_between 
##        0.033        0.977        0.033        0.066

The inspection of the standardized parameters estimated by the weak-invariance model reveals significant factor loadings ranging from 0.57 to 0.99. The model also estimates significant correlations among latent variables in the expected directions, with the only exception of that between demands and control at level 2 (not significant). Overall, these results support the validity of the measurement model hypothesized for the considered items.

# factor loadings from the selected model (weak invariance)
p <- standardizedsolution(fit.winv) # standardized coefficients
p[p$op=="=~",] # selecting factor loadings
# correlations among latent factors
p[p$lhs%in%c("NegVal_w","taskDem_w","taskCon_w") & p$lhs != p$rhs & p$op=="~~",] # level 1
p[p$lhs%in%c("NegVal_b","taskDem_b","taskCon_b") & p$lhs != p$rhs & p$op=="~~",] # level 2


1.6.4. Level-specific reliability

Finally, we use the MCFA model selected above to compute level-specific McDonald’s \(\omega\) coefficients for each scale (see Geldhof et al. 2014). We can see that all \(\omega\) coefficients are satisfactory with values higher than 0.70 and higher coefficients at level 2 than at level 1.

# omega within negative valence
sl <- p[p$op=="=~" & substr(p$rhs,1,1)=="v","est.std"][1:3] # selecting factor loadings at level 1
round( sum(sl)^2 / # omega = sum of squared loadings /
         (sum(sl)^2 + sum(1 - sl^2)) ,2) # (sum of squared loadings + residual variances)
## [1] 0.73
# omega within - task demands
sl <- p[p$op=="=~" & substr(p$rhs,1,1)=="d","est.std"][1:4]
round( sum(sl)^2 / (sum(sl)^2 + sum(1 - sl^2)) ,2) 
## [1] 0.83
# omega within - task control
sl <- p[p$op=="=~" & substr(p$rhs,1,1)=="c","est.std"][1:3] 
round( sum(sl)^2 / (sum(sl)^2 + sum(1 - sl^2)) ,2) 
## [1] 0.74
# omega between - negative valence
sl <- p[p$op=="=~" & substr(p$rhs,1,1)=="v","est.std"][4:6]
round( sum(sl)^2 / (sum(sl)^2 + sum(1 - sl^2)) ,2) 
## [1] 0.94
# omega between - task demands
sl <- p[p$op=="=~" & substr(p$rhs,1,1)=="d","est.std"][5:6] 
round( sum(sl)^2 / (sum(sl)^2 + sum(1 - sl^2)) ,2) 
## [1] 0.95
# omega between - task control
sl <- p[p$op=="=~" & substr(p$rhs,1,1)=="c","est.std"][4:6]
round( sum(sl)^2 / (sum(sl)^2 + sum(1 - sl^2)) ,2) 
## [1] 0.91

Of note, the same coefficients can be obtained more effectively (i.e., without fitting MCFA models) by using the omegaSEM function of the multilevelTools package.

# loading multilevelTools library
library(multilevelTools)

# Negative valence
omegaSEM(items=paste0("v",1:3), id ="ID", data=ild)$Results
# Task demand
omegaSEM(items=paste0("d",1:4), id ="ID", data=ild)$Results
# Task control
omegaSEM(items=paste0("c",1:3), id ="ID", data=ild)$Results


1.7. Composite scores

Here, we compute the composite scores for each scale by averaging the corresponding item scores. Then we compute the cluster-mean and the cluster-mean-centered versions of the composite scores using the same procedures shown in Step 5. As done above, we show how to implement this step by using both base R and, alternatively, the tidyverse syntax.

Base R

With base R, we use the apply function to compute the composite scores NV, TD, and TC by computing the mean score by row. Then, we use the same code shown in section 1.5 to compute the cluster-mean (named NVb, TDb, and TCb) and cluster-mean-centered scores (named NVw, TDw, and TCw).

# computing composite scores
ild$NV <- apply(ild[,c("v1","v2","v3")],1,mean,na.rm=TRUE) # Negative Valence
ild$TD <- apply(ild[,c("d1","d2","d3","d4")],1,mean,na.rm=TRUE) # Task Demands
ild$TC <- apply(ild[,c("c1","c2","c3")],1,mean,na.rm=TRUE) # Task Control

# selecting variable names
VarNames <- c("NV","TD","TC")

# computing cluster-mean values of time-varying variables (see section 1.5)
means <- aggregate(x=ild[,VarNames],by=list(ild$ID),FUN=mean) 
colnames(means) <- c("ID",paste0(VarNames,"b"))
ild <- plyr::join(ild,means,by="ID")

# computing cluster-mean-centered values (see section 1.5)
for(VarName in VarNames){ 
  ild[,paste0(VarName,"w")] <- ild[,VarName] - ild[,paste0(VarName,"b")] } 

# showing example variables
ild[,c("ID","day","beep","NV","NVb","NVw")]

Here, we visualize the distributions of the resulting composite scores. We can see that composite scores are quite symmetrically distributed, although with some positive skewness for negative valence. Cluster-mean-centered score distributions are more symmetric than cluster-mean distributions.

# visualizing composite score distributions
par(mfrow=c(1,3))
for(VarName in VarNames){ 
  hist(ild[,VarName],main=VarName,xlab="",breaks=30) }

# visualizing cluster means of composite scores
for(VarName in paste0(VarNames,"b")){
  hist(ild[!duplicated(ild$ID),VarName],main=VarName,xlab="",breaks=30) }

# visualizing cluster-mean-centered composite scores
for(VarName in paste0(VarNames,"w")){ 
  hist(ild[,VarName],main=VarName,xlab="",breaks=30) }


Tidyverse

Here, we replicate the same operations in two alternative ways based on the tidyverse syntax (see Wickham et al., 2023). In option A, we use the pipe operator %>% to concatenate operations, the group_by function to group operations by participant ID, and the mutate function to specify which operations should be applied (i.e., computing composite scores and their cluster means and cluster-mean-centered values). In option B, we directly use the mutate function to specify all operations to be applied and the grouping variable (specified with the argument .by).

# loading tidyverse package collection
library(tidyverse)

# option A: mutate and group_by
ild_tidyverse_A <- 
  ild %>%
  group_by(ID) %>% # grouping operations by cluster variable "ID"
         # computing composite scores
  mutate(NV = mean(c(v1,v2,v3)), 
         TD = mean(c(d1,d2,d3,d4)),
         TC = mean(c(c1,c2,c3)),
         # computing cluster-mean variables
         NV_mean = mean(NV),
         TD_mean = mean(TD),
         TC_mean = mean(TC),
         # computing cluster-mean-centered variables
         NV_cmc = NV - NV_mean,
         TD_cmc = TD - TD_mean,
         TC_cmc = TC - TC_mean) 
ild_tidyverse_A[,c("ID","day","beep","c1","c1_mean","c1_cmc","d1","d1_mean","d1_cmc")]
# option B: mutate with ".by"
ild_tidyverse_B <- 
  mutate(ild,
         # computing composite scores
         NV = mean(c(v1,v2,v3)), 
         TD = mean(c(d1,d2,d3,d4)),
         TC = mean(c(c1,c2,c3)),
         # computing cluster-mean variables
         NV_mean = mean(NV),
         TD_mean = mean(TD),
         TC_mean = mean(TC),
         # computing cluster-mean-centered variables
         NV_cmc = NV - NV_mean,
         TD_cmc = TD - TD_mean,
         TC_cmc = TC - TC_mean,
         .by = ID) # grouping operations by cluster variable "ID"
ild_tidyverse_B[,c("ID","day","beep","c1","c1_mean","c1_cmc","d1","d1_mean","d1_cmc")]


1.8. Lagging and leading

Here, we provide some code exemplifying how to manipulate ILD data to move a variable (task demands) one time point backward (lagging) or forward (leading) , although such transformed variables are not used in the following analyses. As done above, we show how to implement this step by using both base R and, alternatively, the tidyverse syntax.

Base R

With base R, lagging is implemented with a for-loop that pastes the variable value from the previous row if the values of both participant (i.e., ID) and time identifiers (i.e., day) are equal to those of the previous row. Similarly, leading is implemented with a for-loop the pastes the variable value from the following row if the participant and time values are equal to those of the following row. Here, we show an example with the variable TD.

# saving data as an alternative dataset
ild_baseR <- ild[,c("ID","day","TD")]

# lagging TD variable
for(i in 2:nrow(ild)){ # for each row in the ild dataset
  if(ild[i,"ID"] == ild[i-1,"ID"] & # IF same ID of the previous row... 
     ild[i,"day"] == ild[i-1,"day"]){ # ...AND same day of the previous row...
    ild_baseR[i,"TD.lag"] <- ild[i-1,"TD"] # ...paste the value of the previous row
  }}

# leading TD variable
for(i in 1:(nrow(ild)-1)){ # for each row in the ild dataset
  if(ild[i,"ID"] == ild[i+1,"ID"] & # IF same ID of the next row... 
     ild[i,"day"] == ild[i+1,"day"]){ # ...AND same day of the next row...
    ild_baseR[i,"TD.lead"] <- ild[i+1,"TD"] # ...paste the value of the next row
  }}

# showing original, lagged, and led variable
ild_baseR[,c("ID","day","TD","TD.lag","TD.lead")]


Tidyverse

Here, we replicate the same operations in three alternative ways based on the tidyverse syntax (see Wickham et al., 2023), all of which uses the lag and the lead, functions within the mutate function. In option A, In option A, we use the pipe operator %>% to concatenate operations, the group_by function to group operations by participant ID and day, and the mutate, lag, and lead functions to specify which operations should be applied (i.e., lagging and leading by n = 1 within the same day and the participant). In option B, we directly use the mutate function to specify both the operations to be applied and the two grouping variables (specified with the argument .by). Finally, option C is an extension of option B where we use the across function to repeat the operations specified in the .fns argument across all the columns specified in the .cols argument of the mutate function. In this way, it is possible to avoid manually rewriting the same operations for each variable, as in option A and B.

# loading tidyverse package collection
library(tidyverse)

# option A: mutate and group_by
ild_tidyverse_A <- 
  ild %>%
  group_by(ID,day) %>% # grouping operations by cluster variable "ID"
  mutate(TD.lag = lag(TD, n = 1), # lagging the TD variable
         TD.lead = lead(TD, n = 1)) # leading the TD variableriable
ild_tidyverse_A[,c("ID","day","TD","TD.lag","TD.lead")] # showing data
# option B: mutate with ".by"
ild_tidyverse_B <- 
  mutate(ild,
         TD.lag = lag(TD, n = 1), # lagging the TD variable
         TD.lead = lead(TD, n = 1), # leading the TD variable
         .by = c(ID,day)) # grouping operations by cluster variable "ID"
ild_tidyverse_B[,c("ID","day","TD","TD.lag","TD.lead")] # showing data
# option C: repeat option B over multiple columns using the "across" command
ild_tidyverse_C <-
  mutate(ild,
         across(
           # selecting all the columns on which repeating the operations
           .cols = c("TD","TC","NV"), 
           .fns = list( # list of operations to be repeated
             lag =~ lag(.x, n = 1), # lagging the TD variable
             lead =~ lead(.x, n = 1) )), # leading the TD variable
         .by = c(ID,day)) # grouping operations by cluster variable "ID"
ild_tidyverse_C[,c("ID","day","TD","TD_lag","TD_lead","TC","TC_lag","TC_lead")] # showing data


2. Data analysis

2.1. Descriptive statistics

Here, we compute descriptive statistics, namely the number of included observations and participants, mean, SD, and frequencies of each included variables, the ICC(1) of time-varying variables, and the level-specific correlations among the included quantitative variables. To illustrate how the same output can be obtained in multiple ways, we compute descriptive statistics both using base R syntax and, alternatively, using the psych package.

Base R

With base R, the mean and standard deviation of quantitative variables and the frequency of categorical variables are computed within a for-loop. A second for-loop is then used to extract the variance components from intercept-only linear mixed-effects regression models, which are used to estimate the ICC(1). Finally, we use the cor function to compute and merge within- and between-individual correlations.

# number of included observations
cat("Level 1:",nrow(ild),"observations; Level 2:",nrow(ild[!duplicated(ild$ID),]),"participants")
## Level 1: 1378 observations; Level 2: 121 participants
# selecting variable names
VarNames <- c("NV","TD","TC")

# computing mean and standard deviation
desc <- c() # empty vector to be filled with descriptive stats
for(VarName in VarNames){ # for each time-varying variable...
  desc[VarName] <- # ...computing mean and SD and pasting them together
    paste0(round(mean(ild[,VarName]),2),
           " (",round(sd(ild[,VarName]),2),")") } 
desc["age"] <- # same thing for age but based on the wide-form dataset
  paste0(round(mean(prelqs$age),2), 
         " (",round(sd(prelqs$age),2),")") 
desc["gender"] <- # frequency and % of categorical variables (gender)
  paste0(table(prelqs$gender)[1]," F (",
         round(100*prop.table(table(prelqs$gender)),2),"%)")

# computing ICC(1) based on variance decomposition
library(lme4) # loading package to fit linear mixed-effects regression models
icc <- c() # empty vector to be filled with ICC values
for(VarName in VarNames){ # foreach time-varying variable..
  fit <- lmer(as.formula(paste(VarName,"~ (1|ID)")), data = ild) # fitting null multilevel model
  tau00 <- summary(fit)$varcor$ID[[1]] # variance of the random intercept
  sigma2 <- summary(fit)$sigma^2 # residual variance
  icc <- c(icc, VarName = round(tau00/(tau00 + sigma2),2)) # ICC = tau00/(tau00+sigma2)
  }

# computing level-specific correlations among time-varying variables
cor1 <- round(cor(ild[,paste0(VarNames,"w")]),2) # level 1 (cluster-mean-centered)
cor2 <- round(cor(ild[!duplicated(ild$ID),paste0(VarNames,"b")]),2) # level 2 (cluster means)
cor1[lower.tri(cor1)] <- cor2[lower.tri(cor2)] # merging the two matrices
rownames(cor1) <- colnames(cor1) <- VarNames # adding variable labels

# adding level-2 correlations with age + empty row for gender
cor1 <- rbind(cor1,
              cor(x=ild[!duplicated(ild$ID),c(paste0(VarNames,"b"),"age")],)[4,1:3],
              matrix(rep(NA,3),nrow=1))
rownames(cor1)[4:5] <- c("age","gender")

# joining and printing descriptive stats, ICC, and correlations
cbind(data.frame(Desc = desc, ICC = c(icc, NA, NA)), round(cor1, 2))


psych

Here, we illustrate how the same operations can be optimized with the psych package. First, we use the describe function to compute the number of observations, mean and standard deviation of each quantitative variable. Second, we use the statBy function to compute ICCs(1) for each time-varying variable and level-specific correlations. Finally, we show how to extract and report the significance level of each correlation coefficient.

# loading psych package
library(psych)

# computing number of observations, mean and sd
desc <- rbind(describe(ild[,c("NV","TD","TC")])[,c("n","mean","sd")], # time-varying
              describe(prelqs[,"age"])[,c("n","mean","sd")]) # time-invariant

# computing ICC(1)
icc <- c(round(statsBy(ild[,c("NV","TD","TC")],group=ild$ID)$ICC1[1:3],2)) 

# computing level-specific correlations
cors <- psych::statsBy(ild[,c("NV","TD","TC","age")],group=ild$ID)
cors$rwg[lower.tri(cors$rwg)] <- cors$rbg[lower.tri(cors$rbg)] # merging lv-1 & lv-2 correlations

# joining and printing descriptive stats, ICC, and correlations
desc <- cbind(data.frame(Desc = desc, ICC = c(icc, NA)), round(cors$rwg[,1:3], 2))
rownames(desc) <- c("NV","TD","TC","age") # renaming rows
colnames(desc) <- c("n","mean","SD","ICC","NV","TD","TC") # renaming columns
desc # printing descriptive stats
# optional: adding asterisks for p-values
cors$pwg[lower.tri(cors$pwg)] <- cors$pbg[lower.tri(cors$pbg)] # merging lv-1 & lv-2 p-values
p <- matrix(nrow=4,ncol=3) # creating empty matrix to be filled with significance levels
for(i in 1:4){
  for(j in 1:3){
    if(!is.na(cors$pwg[i,j]) & cors$pwg[i,j] != 1){
      desc[i,j+4] <- paste0(desc[i,j+4], # adding asterisks to correlation coefficients
                            ifelse(cors$pwg[i,j] < .001,
                                   "***",
                                   ifelse(cors$pwg[i,j] < .01,
                                          "**",
                                          ifelse(cors$pwg[i,j] < .05,
                                                 "*","")))) }}}
desc # printing descriptive stats


2.2. Regression models

Here, we fit and print the two illustrative models testing JDC hypotheses. This is done by including cluster-mean-centered task demands TDw and task control TCw and their level-1 interaction in Model 1, whereas model 2 includes and tests the cross-level interaction between cluster-mean-centered task demands TDw and the cluster means of task control TCb. In both models, we include age and gender as level-2 covariates and a random slope for task demands. Both models are fitted with the REML estimator (see McNeish, 2017).

# loading required packages
library(lme4); library(sjPlot)
# fitting models
fit1 <- lmer(NV ~ TDw * TCw + age + gender + (TDw|ID), data = ild)
fit2 <- lmer(NV ~ TDw * TCb + age + gender + (TDw|ID), data = ild)

# printing output table
tab_model(fit1, fit2,
          show.se = TRUE, collapse.se = TRUE, p.val = "wald", # Wald approximation
          show.ci = FALSE, show.icc = FALSE)
  NV NV
Predictors Estimates p Estimates p
(Intercept) 3.20
(0.29)
<0.001 4.80
(0.43)
<0.001
TDw 0.10
(0.03)
0.002 0.37
(0.13)
0.005
TCw -0.15
(0.02)
<0.001
age 0.00
(0.01)
0.583 -0.00
(0.01)
0.665
gender [M] -0.02
(0.15)
0.897 -0.06
(0.14)
0.663
TDw × TCw -0.02
(0.02)
0.350
TCb -0.32
(0.07)
<0.001
TDw × TCb -0.06
(0.03)
0.046
Random Effects
σ2 0.59 0.61
τ00 0.59 ID 0.49 ID
τ11 0.04 ID.TDw 0.05 ID.TDw
ρ01 0.06 ID -0.03 ID
N 121 ID 121 ID
Observations 1378 1378
Marginal R2 / Conditional R2 0.031 / 0.533 0.092 / 0.518

Note that the marginal and conditional \(R^2\) are estimates of the proportion of negative valence variance explained by fixed effects only and by both fixed and random effects, respectively.


Finally, we plot the estimated interactions.

# loading required packages
library(ggplot2); library(gridExtra)
# setting graphical parameters
sd_tc1 <- round(sd(ild$TCw),2) # computing TC standard dev. at level 1
mean_tc2 <- round(mean(means$TCb),2) # computing mean TC at level 2
sd_tc2 <- round(sd(means$TCb),2) # computing TC standard dev. at level 2
labs <- c("-1 SD","+1 SD") # setting legend labels
cols <- c("black","#666666") # setting colors
lins <- c("solid","dashed") # setting line types

# plotting
p <- grid.arrange(
  # Model 1 (TCw +/- 1 SD)
  plot_model(fit1,type="pred",terms=c("TDw",paste0("TCw [",-sd_tc1,",",sd_tc1,"]"))) + 
    scale_color_manual(labels=labs,values=cols) +
    scale_linetype_manual(labels=labs,values=lins) + 
    scale_fill_manual(labels=labs,values=cols) + ggtitle("") + 
    xlab("Task demand (within)") + ylab("Negative valence") +
    guides(color=guide_legend(title="Task Control\n(within)")),
  # Model 2 (Mean TCb +/- 1 SD)
  plot_model(fit2,type="pred",
             terms=c("TDw",paste0("TCb [",mean_tc2-sd_tc1,",",mean_tc2+sd_tc1,"]"))) +
    scale_color_manual(labels=labs,values=cols) +
    scale_linetype_manual(labels=labs,values=lins) + 
    scale_fill_manual(labels=labs,values=cols) + ggtitle("") + 
    xlab("Task demand (within)") + ylab("Negative valence") +
    guides(color=guide_legend(title="Task control\n(between)")), nrow=1)

# exporting figure
ggsave("fig2.png", plot = p, dpi = 300)


3. Multiverse approach

Here, we integrate the code provided for each step into a unified function ild.manip to illustrate how results might change based on data manipulation choices. Note that some of the function arguments are set by default as required by our illustrative example.

show ild.manip

#' @title Intensive longitudinal data manipulation
#' @param long = long-form dataset (data.frame)
#' @param wide = wide-form dataset (data.frame)
#' @param cluster = name of the cluster variable identifying participants (character)
#' @param long.respTime = name of the time variable in the long-form dataset (character)
#' @param respTime.format = time format used by the long.respTime variable (character) (see ?strptime)
#' @param scheduledTimes = list of three-element character vectors reporting the minimum, central, and maximum time for each scheduled measurement using the same time format set in the scheduledTimes.format argument
#' @param scheduledTimes.format = time format (without date) used in the scheduledTimes argument (character) (default "%H:%M:%S")
#' @param long.variables = list of variable names in the long-form dataset (i.e., for each variable, it should include a list element named with the variable name and including a vector of variable names reporting the name of each item; with single-item measures only the variable name should be specified, without any vector)
#' @param wide.variables = list of variable names in the wide-form dataset (see long.variables)
#' @param remove.first.beep = logical value determining whether the first measurement occasion within each day should be excluded (TRUE) or not (FALSE, default)
#' @param remove.first.day = logical value determining whether the first day of each participant should be excluded (TRUE) or not (FALSE, default)
#' @param listwise.del = logical value determining whether a list-wise deletion should be applied (TRUE) or not (FALSE, default)
#' @param compliance.cutoff = numeric value indexing the minimum number of observations or compliance rate cut-off used to exclude participants (NA by default, meaning that all participants are included)
#' @param compliance.type = character value determining whether the compliance.cutoff value is expressed as the minimum number of observations (compliance.type = "obs") or as the minimum compliance rate (compliance.type="perc")
#' @param max.nobs = integer indexing the maximum number of responses per participant (required when compliance.type="perc")

ild.manip <- function(long, wide, cluster = "ID", long.respTime = "RunTimestamp",
                      respTime.format = "%Y-%m-%d %H:%M:%S",
                      scheduledTimes = list(c("09:15:00","09:30:00","10:15:00"),  # beep 1
                                            c("10:20:00","10:30:00","10:40:00"),  # beep 2
                                            c("11:50:00","12:00:00","12:10:00"),  # beep 3
                                            c("13:20:00","13:30:00","13:40:00"),  # beep 4
                                            c("14:50:00","15:00:00","15:10:00"),  # beep 5
                                            c("16:20:00","16:30:00","16:40:00"),  # beep 6
                                            c("17:50:00","18:00:00","18:10:00")), # beep 7
                      scheduledTimes.format = "%H:%M:%S",
                      long.variables = list(NV = c("v1","v2","v3"), 
                                            TD = c("d1","d2","d3","d4"), 
                                            TC = c("c1","c2","c3")),
                      wide.variables = list("gender","age"), 
                      remove.first.beep = FALSE, remove.first.day = FALSE,
                      listwise.del = FALSE, compliance.cutoff = NA, 
                      compliance.type = c("obs","perc"), max.nobs = 18){
  
  # renaming variables
  colnames(long)[which(colnames(long)==cluster)] <- "ID" # cluster variable in the long dataset
  colnames(wide)[which(colnames(wide)==cluster)] <- "ID" # cluster variable in the wide dataset
  colnames(long)[which(colnames(long)==long.respTime)] <- "respTime" # time variable in the long dataset
  
  # 1) data reading (removing unuseful columns).........................................................
  #.....................................................................................................
  long <- long[,which(colnames(long) %in% c("ID","respTime",as.character(unlist(long.variables))))]
  wide <- wide[,which(colnames(wide) %in% c("ID",as.character(unlist(wide.variables))))]
  
  # print info
  cat("Data pre-processing...\n\n")
  
  # 2) temporal synchronization..........................................................................
  #......................................................................................................
  long$time <- as.POSIXct(strftime(as.POSIXct(long$respTime, format="%Y-%m-%d %H:%M:%S"),
                                   format="%H:%M:%S"),format="%H:%M:%S") # resp time
  long$date <- as.Date(substr(long$respTime,1,10),format="%Y-%m-%d") # resp date without time
  # creating 'day' variable base on response dates
  long$day <- 1 
  for(i in 2:nrow(long)){ if(long[i,"ID"] != long[i-1,"ID"]){ long[i,"day"] <- 1 } else {
      if(!is.na(long[i,"date"]) & !is.na(long[i-1,"date"]) & 
         as.POSIXlt(long[i,"date"])$wday != as.POSIXlt(long[i-1,"date"])$wday){
        long[i,"day"] <- long[i-1,"day"] + 1 } else{ long[i,"day"] <- long[i-1,"day"] }}}
  # creating 'beep' variable based on scheduled timestamps
  if(!is.na(scheduledTimes[[1]][1])){ central.times <- c() # saving vector of central times
    for(i in 1:length(scheduledTimes)){ # assign beep value depending on each couple of min-max
      long[!is.na(long$time) & 
             long$time > (as.POSIXct(scheduledTimes[[i]][1], 
                                     format = scheduledTimes.format) - 10*60) & 
            long$time < (as.POSIXct(scheduledTimes[[i]][3], 
                                    format = scheduledTimes.format) + 10*60),"beep"] <- i 
      central.times <- c(central.times, scheduledTimes[[i]][2]) }
  # when time is outside the scheduled interval, the closest 'beep' is assigned
  for(i in 1:nrow(long)){ require(birk) 
    if(is.na(long[i,"beep"]) & !is.na(long[i,"time"])){ 
      long[i,"beep"] <- which.closest(as.POSIXct(central.times, format = scheduledTimes.format),
                                      long[i,"time"]) }}}
  
  # 3) data cleaning.....................................................................................
  #......................................................................................................
  n1.long<-nrow(long) # save N.obs for comparison
  n2.long<-length(table(long$ID))
  n2.wide<-length(table(wide$ID))
  n <- 1; for(i in 1:length(wide.variables)){ if(length(wide.variables[i]) > 1){ n <- n + 1 }}
  # 3.1) removing missing resps from the wide-form dataset...............................................
  if(n == 1){ wide <- na.omit(wide[,c("ID",unlist(wide.variables))]) 
  } else { VarNames <- "ID"
    for(i in 1:length(wide.variables)){ VarNames <- c(VarNames,names(wide.variables[i])) }
    wide <- na.omit(wide[,VarNames]) }
  long <- long[long$ID %in% as.character(wide$ID),] # removing cases that are not included in the wide dataset
  long$ID <- as.factor(as.character(long$ID)) # resetting levels
  cat("Data cleaning:\n-",n1.long-nrow(long),"obs,",n2.long-nlevels(long$ID),
      "participants not in the wide dataset")
  # 3.2) removing cases with missing responses to the long-form dataset..................................
  long <- long[!is.na(long$respTime),] 
  long$ID <- as.factor(as.character(long$ID)) # resetting levels
  wide <- wide[wide$ID %in% levels(long$ID),] # removing cases that are not included in the long dataset
  wide$ID <- as.factor(as.character(wide$ID)) # resetting levels
  cat("\n-",n2.wide-nrow(wide),"participants not in the long dataset")
  # 3.3) removing first observation within each day......................................................
  n1.long<-nrow(long); n2.long<-nlevels(long$ID) # saving sample sizes for comparison
  if(isTRUE(remove.first.beep)){ 
    if(!is.na(scheduledTimes[[1]][1])){ 
      long <- long[long$beep!=1,] # removing 1st 'beep' when scheduledTimes are specified
    } else { LONG <- long[0,] # removing the first daily observation when scheduledTimes are NOT specified
      long$IDday <- paste(long$ID,long$day) # creating identifier based on both ID and day
      for(obs in levels(as.factor(long$IDday))){ LONG <- rbind(LONG,long[long$IDday == obs,][-1,]) }
      long <- LONG }}
  # 3.4) removing first day..............................................................................
  if(isTRUE(remove.first.day)){ long <- long[long$day!=1,] } 
  long$ID <- as.factor(as.character(long$ID)) # resetting levels
  if(isTRUE(remove.first.beep) | isTRUE(remove.first.day)){
    cat("\n-",n1.long-nrow(long),"obs,",n2.long-nlevels(long$ID),
        "participants following the removal of the 1st",
        ifelse(isTRUE(remove.first.beep) & isTRUE(remove.first.day),"day and the 1st daily survey",
               ifelse(isTRUE(remove.first.beep),"daily survey","day"))) }
  # 3.5) list-wise deletion..............................................................................
  n1.long<-nrow(long); n2.long<-nlevels(long$ID) # saving sample sizes for comparison
  if(isTRUE(listwise.del)){ long <- na.omit(long[,c("ID","respTime","day",as.character(unlist(long.variables)))]) 
    long$ID <- as.factor(as.character(long$ID)) # resetting levels
    cat("\n-",n1.long-nrow(long),"obs,",n2.long-nlevels(long$ID),
        "participants following list-wise deletion")}
  # 3.5) excluding participants based on compliance rate.................................................
  if(!is.na(compliance.cutoff)){ n1.long<-nrow(long); n2.long<-nlevels(ild$ID) # saving sample sizes
    if(compliance.type=="obs"){ # compliance based on overall number of observations
      for(day in min(as.integer(long$day)):max(as.integer(long$day))){ 
        for(i in 1:nrow(wide)){ # computing no. obs per day and participant
          wide[i,paste0("n.day",day)] <- nrow(long[long$ID==as.character(wide[i,"ID"]) & long$day==day,]) }
        colnames(wide)[ncol(wide)] <- "nDay" # renaming column
        wide <- wide[wide$nDay >= compliance.cutoff,] # removing participants
        colnames(wide)[ncol(wide)] <- paste0("n.day",day) }
    } else if(compliance.type=="perc"){ # compliance based on percentage of responses
        for(i in 1:nrow(wide)){ 
          wide[i,"compRate"] <- 100*nrow(long[long$ID==as.character(wide[i,"ID"]),])/max.nobs }
      wide <- wide[wide$compRate >= compliance.cutoff,] }
    long <- long[long$ID %in% as.character(wide$ID),] # removing the same participants from the long dataset
    long$ID <- as.factor(as.character(long$ID)) # resetting levels
    cat("\n-",n1.long-nrow(long),"obs,",n2.long-nlevels(long$ID),
      "participants with",ifelse(compliance.type=="obs",paste("less than",compliance.cutoff,"obs per day"),
                                 paste("compliance rate <",compliance.cutoff,"%"))) }
  
  # 4) data merging........................................................................................
  #........................................................................................................
  require(plyr)
  long <- join(long, wide, by = "ID")
  
  # 5) computing composite scores..........................................................................
  #........................................................................................................
  n <- 1; for(i in 1:length(long.variables)){ if(length(long.variables[[i]]) > 1){ n <- n + 1 }}
  if(n > 1){
    for(i in 1:length(long.variables)){
      long[,names(long.variables)[i]] <- apply(long[,long.variables[[i]]],1,mean,na.rm=TRUE) }}
  
  # 6) data centering......................................................................................
  #........................................................................................................
  if(n > 1){
    for(VarName in names(long.variables)){ 
      colnames(long)[colnames(long)==VarName] <- "VarName" # changing variable name
      clust.means <- aggregate(x = long$VarName, # cluster means
                               by = list(long$ID), FUN = mean, na.rm = TRUE) 
      colnames(clust.means) <- c("ID","VarNameb") # renaming variable
      long <- join(long, clust.means, by="ID") # joining cluster mean to long-form dataset
      long$VarNamew <- long$VarName - long$VarNameb # cluster mean centering
      colnames(long) <- gsub("VarName",VarName,colnames(long)) }} # back to the original variable name
  
  # print info
  long$ID <- as.factor(as.character(long$ID))
  cat("\n\nTotal number of retained observations =",nrow(long),"from",nlevels(long$ID),"participants")
  
  # returning data
  return(long) }


3.1. Multiverse of datasets

First, we apply the function to the raw datasets by considering alternative data manipulation scenarios.

# reading raw datasets
long <- read.csv("S5_processedData/ESM_processed.csv", stringsAsFactors = TRUE) # ILD dataset
wide <- read.csv("S5_processedData/RETRO_processed.csv", stringsAsFactors = TRUE) # preliminary questionnaire

# scenario #1: same settings as above (a part from the single careless response, which is retained)
m1 <- ild.manip(long, wide, 
                remove.first.beep = TRUE,  listwise.del = TRUE, 
                compliance.cutoff = 2, compliance.type = "obs")
## Data pre-processing...
## 
## Data cleaning:
## - 67 obs, 9 participants not in the wide dataset
## - 45 participants not in the long dataset
## - 260 obs, 0 participants following the removal of the 1st daily survey
## - 71 obs, 0 participants following list-wise deletion
## - 202 obs, 0 participants with less than 2 obs per day
## 
## Total number of retained observations = 1379 from 121 participants
# scenario #2: no data cleaning (i.e., retaining all available observations)
m2 <- ild.manip(long, wide)
## Data pre-processing...
## 
## Data cleaning:
## - 67 obs, 9 participants not in the wide dataset
## - 45 participants not in the long dataset
## 
## Total number of retained observations = 1912 from 166 participants
# scenario #3: removing first response regardless of response time
m3 <- ild.manip(long, wide, 
                remove.first.beep = TRUE,  listwise.del = TRUE, 
                compliance.cutoff = 2, compliance.type = "obs",
                scheduledTimes = NA)
## Data pre-processing...
## 
## Data cleaning:
## - 67 obs, 9 participants not in the wide dataset
## - 45 participants not in the long dataset
## - 471 obs, 4 participants following the removal of the 1st daily survey
## - 60 obs, 2 participants following list-wise deletion
## - 237 obs, 13 participants with less than 2 obs per day
## 
## Total number of retained observations = 1144 from 108 participants
# scenario #4: removing first day
m4 <- ild.manip(long, wide, 
                remove.first.day = TRUE,   listwise.del = TRUE, 
                compliance.cutoff = 2, compliance.type = "obs")
## Data pre-processing...
## 
## Data cleaning:
## - 67 obs, 9 participants not in the wide dataset
## - 45 participants not in the long dataset
## - 692 obs, 7 participants following the removal of the 1st day
## - 206 obs, 1 participants following list-wise deletion
## - 84 obs, -5 participants with less than 2 obs per day
## 
## Total number of retained observations = 930 from 126 participants
# scenario #5: stricter compliance rate (3+ observations per day)
m5 <- ild.manip(long, wide, 
                remove.first.beep = TRUE, listwise.del = TRUE, 
                compliance.cutoff = 3, compliance.type = "obs")
## Data pre-processing...
## 
## Data cleaning:
## - 67 obs, 9 participants not in the wide dataset
## - 45 participants not in the long dataset
## - 260 obs, 0 participants following the removal of the 1st daily survey
## - 71 obs, 0 participants following list-wise deletion
## - 568 obs, 39 participants with less than 3 obs per day
## 
## Total number of retained observations = 1013 from 82 participants
# scenario #6: compliance rate > 30%
m6 <- ild.manip(long, wide, 
                remove.first.beep = TRUE, listwise.del = TRUE, 
                compliance.cutoff = 30, compliance.type = "perc")
## Data pre-processing...
## 
## Data cleaning:
## - 67 obs, 9 participants not in the wide dataset
## - 45 participants not in the long dataset
## - 260 obs, 0 participants following the removal of the 1st daily survey
## - 71 obs, 0 participants following list-wise deletion
## - 105 obs, -13 participants with compliance rate < 30 %
## 
## Total number of retained observations = 1476 from 134 participants
# scenario #7: compliance rate > 75%
m7 <- ild.manip(long, wide, 
                remove.first.beep = TRUE, listwise.del = TRUE, 
                compliance.cutoff = 75, compliance.type = "perc")
## Data pre-processing...
## 
## Data cleaning:
## - 67 obs, 9 participants not in the wide dataset
## - 45 participants not in the long dataset
## - 260 obs, 0 participants following the removal of the 1st daily survey
## - 71 obs, 0 participants following list-wise deletion
## - 1231 obs, 98 participants with compliance rate < 75 %
## 
## Total number of retained observations = 350 from 23 participants
# scenario #8: (4) and (7)
m8 <- ild.manip(long, wide, 
                remove.first.beep = TRUE, listwise.del = TRUE, 
                compliance.cutoff = 30, compliance.type = "perc",
                scheduledTimes = NA)
## Data pre-processing...
## 
## Data cleaning:
## - 67 obs, 9 participants not in the wide dataset
## - 45 participants not in the long dataset
## - 471 obs, 4 participants following the removal of the 1st daily survey
## - 60 obs, 2 participants following list-wise deletion
## - 113 obs, -3 participants with compliance rate < 30 %
## 
## Total number of retained observations = 1268 from 124 participants
# scenario #9: (4) and (8)
m9 <- ild.manip(long,wide, 
                 remove.first.beep = TRUE, listwise.del = TRUE, 
                 compliance.cutoff = 75, compliance.type = "perc",
                scheduledTimes = NA)
## Data pre-processing...
## 
## Data cleaning:
## - 67 obs, 9 participants not in the wide dataset
## - 45 participants not in the long dataset
## - 471 obs, 4 participants following the removal of the 1st daily survey
## - 60 obs, 2 participants following list-wise deletion
## - 1165 obs, 107 participants with compliance rate < 75 %
## 
## Total number of retained observations = 216 from 14 participants


3.2. Results

Here, we fit the same models fitted above on each generated dataset, and we summarize the results by reporting the value TRUE (i.e., significant) or FALSE (i.e., non-significant) for each main and interactive effect of interest. We can see that the results obtained above are quite robust across the considered scenarios. Specifically, the most robust findings concern the negative level-1 effect of task control (significant across all scenarios) and the lack of level-1 interaction (non-significant across all scenarios). The main effect of task demands estimated by Model 1 is also quite robust, being non-significant only in one case (i.e., removal of the first day). Finally, the main and interactive effects estimated by Model 2 become non-significant only when a compliance rate of 70% is applied, yet the resulting datasets are very small (i.e., n1 ranging from 216 to 358, n2 ranging from 14 to 23). Overall, such robustness checks support the generalizability of our findings.

# multiverse of datasets as a list
m <- list(m1,m2,m3,m4,m5,m6,m7,m8,m9)

# data.frame of results to be filled
out <- data.frame(matrix(nrow=0,ncol=8))
colnames(out) <- c("N1","N2","m1.TDw","m1.TCw","m1.int","m2.TDw","m2.TCb","m2.int")

# fitting models on each dataset
for(i in 1:length(m)){
  fit1 <- lmer(NV ~ TDw * TCw + age + gender + (TDw|ID), data = m[[i]])
  fit2 <- lmer(NV ~ TDw * TCb + age + gender + (TDw|ID), data = m[[i]])
  out <- rbind(out, # extracting results (i.e., effects marked as TRUE if Coeff./SE > 1.96, FALSE otherwise)
               data.frame(N1 = length(residuals(fit1)), N2 = as.integer(summary(fit1)$ngrps), # sample sizes
                          m1.TDw=abs(summary(fit1)$coefficients[2,3])>1.96, # model 1 main effects
                          m1.TCw=abs(summary(fit1)$coefficients[3,3])>1.96, 
                          m1.int=abs(summary(fit1)$coefficients[6,3])>1.96, # model 1 interaction
                          m2.TDw=abs(summary(fit2)$coefficients[2,3])>1.96, # model 2 main effects
                          m2.TCb=abs(summary(fit2)$coefficients[3,3])>1.96, 
                          m2.int=abs(summary(fit2)$coefficients[6,3])>1.96)) } # model 2 interaction
cbind(data=c("1. Original","2. All in","3. 1st resp out","4. 1st day out", # printing results
             "5. 3+ obs/day","6. 30% compl","7. 70% compl","8. (4) & (7)","19. (4) & (8)"),out) # naming scenarios


References

  • Caughlin, D. E. (2023). R for HR: An Introduction to Human Resource Analytics Using R. https://rforhr.com/index.html#hragrowth

  • Cranford, J. A., Shrout, P. E., Iida, M., Rafaeli, E., Yip, T., & Bolger, N. (2006). A Procedure for Evaluating Sensitivity to Within-Person Change: Can Mood Measures in Diary Studies Detect Change Reliably? Personality and Social Psychology Bulletin, 32(7), 917–929. https://doi.org/10.1177/0146167206287721

  • Curran, P. G. (2016). Methods for the detection of carelessly invalid responses in survey data. Journal of Experimental Social Psychology, 66, 4-19. https://doi.org/10.1016/j.jesp.2015.07.006

  • Einspruch, E. L. (2022). An Introductory Guide to R: Easing the Learning Curve. Guilford Press.

  • Geldhof, G. J., Preacher, K. J., & Zyphur, M. J. (2014). Reliability estimation in a multilevel confirmatory factor analysis framework. Psychological Methods, 19(1), 72–91. https://doi.org/10.1037/a0032138

  • Wickham, H., Cetinkaya-Rundel, M., & Grolemund G. (2023). R for Data Science: Import, Tidy, Transform, Visualize, and Model (2nd Ed.). O’Reilly. Available at https://r4ds.hadley.nz/

  • Hamaker, E. L., & Grasman, R. P. P. P. (2015). To center or not to center? Investigating inertia with a multilevel autoregressive model. Frontiers in Psychology, 5. https://doi.org/10.3389/fpsyg.2014.01492

  • Huang, J. L., Curran, P. G., Keeney, J., Poposki, E. M., & DeShon, R. P. (2012). Detecting and deterring insufficient effort responding to surveys. Journal of Business and Psychology, 27, 99-114. https://doi.org/10.1007/s10869-011-9231-8

  • Jak, S., & Jorgensen, T. D. (2017). Relating measurement invariance, cross-level invariance, and multilevel reliability. Frontiers in psychology, 8, 1640. https://doi.org/10.3389/fpsyg.2017.01640

  • Kabacoff, R. I. (2022). R in Action: Data analysis and graphics with R and Tidyverse (3rd. Ed). Manning.

  • Karasek, R. A. (1979). Job Demands, Job Decision Latitude, and Mental Strain: Implications for Job Redesign. Administrative Science Quarterly, 24(2), 285–308. https://doi.org/10.2307/2392498

  • McNeish, D. (2017). Small Sample Methods for Multilevel Modeling: A Colloquial Elucidation of REML and the Kenward-Roger Correction. Multivariate Behavioral Research, 52(5), 661–670. https://doi.org/10.1080/00273171.2017.1344538

  • McNulty, K. (2022). Handbook of Regression Modeling in People Analytics: With Examples in R, Python and Julia. CRC Press. Freely available at https://peopleanalytics-regression-book.org/index.html

  • Menghini, L., Pastore, M., & Balducci, C. (2023). Workplace Stress in Real Time: Three Parsimonious Scales for the Experience Sampling Measurement of Stressors and Strain at Work. European Journal of Psychological Assessment, 39(6), 424–432. https://doi.org/10.1027/1015-5759/a000725

  • Shrout, P. E., & Lane, S. P. (2012). Psychometrics. In M. R. Mehl & T. S. Conner (Eds.), Handbook of research methods for studying daily life (pp. 302–320). The Guilford Press.

  • Starbuck, C. (2023). The Fundamentals of People Analytics With Applications in R. Springer. Freely available at https://link.springer.com/book/10.1007/978-3-031-28674-2

  • Wang, L. P., & Maxwell, S. E. (2015). On disaggregating between-person and within-person effects with longitudinal data using multilevel models. Psychological Methods, 20(1), 63–83. https://doi.org/10.1037/met0000030

  • Wickham, H., Çetinkaya-Rundel, M., & Grolemund, G. (2023). R for Data Science: Import, Tidy, Transform, Visualize, and Model Data (2nd Ed.). O’Reilly.


R packages

Auguie, Baptiste. 2017. gridExtra: Miscellaneous Functions for "Grid" Graphics. https://CRAN.R-project.org/package=gridExtra.
Bates, Douglas, Martin Mächler, Ben Bolker, and Steve Walker. 2015. “Fitting Linear Mixed-Effects Models Using lme4.” Journal of Statistical Software 67 (1): 1–48. https://doi.org/10.18637/jss.v067.i01.
Bates, Douglas, Martin Maechler, Ben Bolker, and Steven Walker. 2024. Lme4: Linear Mixed-Effects Models Using Eigen and S4. https://github.com/lme4/lme4/.
Birk, Matthew A. 2016. Birk: MA Birk’s Functions. https://CRAN.R-project.org/package=birk.
Lüdecke, Daniel. 2024. sjPlot: Data Visualization for Statistics in Social Science. https://strengejacke.github.io/sjPlot/.
R Core Team. 2024. R: A Language and Environment for Statistical Computing. Vienna, Austria: R Foundation for Statistical Computing. https://www.R-project.org/.
Revelle, William. 2024. Psych: Procedures for Psychological, Psychometric, and Personality Research. https://personality-project.org/r/psych/.
Rosseel, Yves. 2012. lavaan: An R Package for Structural Equation Modeling.” Journal of Statistical Software 48 (2): 1–36. https://doi.org/10.18637/jss.v048.i02.
Rosseel, Yves, Terrence D. Jorgensen, and Luc De Wilde. 2024. Lavaan: Latent Variable Analysis. https://lavaan.ugent.be.
Wickham, Hadley. 2011. “The Split-Apply-Combine Strategy for Data Analysis.” Journal of Statistical Software 40 (1): 1–29. https://www.jstatsoft.org/v40/i01/.
———. 2016. Ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York. https://ggplot2.tidyverse.org.
———. 2023a. Plyr: Tools for Splitting, Applying and Combining Data. http://had.co.nz/plyr.
———. 2023b. Tidyverse: Easily Install and Load the Tidyverse. https://tidyverse.tidyverse.org.
Wickham, Hadley, Mara Averick, Jennifer Bryan, Winston Chang, Lucy D’Agostino McGowan, Romain François, Garrett Grolemund, et al. 2019. “Welcome to the tidyverse.” Journal of Open Source Software 4 (43): 1686. https://doi.org/10.21105/joss.01686.
Wickham, Hadley, Winston Chang, Lionel Henry, Thomas Lin Pedersen, Kohske Takahashi, Claus Wilke, Kara Woo, Hiroaki Yutani, Dewey Dunnington, and Teun van den Brand. 2024. Ggplot2: Create Elegant Data Visualisations Using the Grammar of Graphics. https://ggplot2.tidyverse.org.
Wolen, Aaron R., Chris H. J. Hartgerink, Ryan Hafen, Brian G. Richards, Courtney K. Soderberg, and Timothy P. York. 2020. osfr: An R Interface to the Open Science Framework.” Journal of Open Source Software 5 (46): 2071. https://doi.org/10.21105/joss.02071.
Wolen, Aaron, and Chris Hartgerink. 2022. Osfr: Interface to the Open Science Framework (OSF). https://docs.ropensci.org/osfr/.
LS0tDQp0aXRsZTogIk1hbmlwdWxhdGlvbiBvZiBpbnRlbnNpdmUgbG9uZ2l0dWRpbmFsIGRhdGEiDQphdXRob3I6ICJMdWNhIE1lbmdoaW5pLCBQaC5ELiwgRW5yaWNvIFBlcmluZWxsaSwgUGguRC4sIENyaXN0aWFuIEJhbGR1Y2NpLCBQaC5ELiINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCmJpYmxpb2dyYXBoeTogW3BhY2thZ2VzLmJpYl0NCm5vY2l0ZTogJ0AqJw0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIHRvY19kZXB0aDogNA0KICAgIGNzczogc3R5bGVzLmNzcw0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQNCiAgdGhlbWU6IHVuaXRlZA0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCjxicj4NCg0KIyBBaW1zIGFuZCBjb250ZW50DQoNClRoZSBwcmVzZW50IGRvY3VtZW50IGluY2x1ZGVzIHRoZSBSIGNvZGUgdG8gYmUgdXNlZCBmb3IgaW1wbGVtZW50aW5nIHRoZSBkYXRhIHByZS1wcm9jZXNzaW5nIHN0ZXBzIHJlcXVpcmVkIG9yIHJlY29tbWVuZGVkIHRvIHByZXBhcmUgaW50ZW5zaXZlIGxvbmdpdHVkaW5hbCBkZXNpZ24gKElMRCkgZGF0YXNldHMgZm9yIGJlaW5nIGFuYWx5emVkIHdpdGggbXVsdGlsZXZlbCBhbmQgb3RoZXIgZGF0YSBhbmFseXNpcyB0ZWNobmlxdWVzLiBBZnRlciBhIGZldyBzZXR0aW5nIHByb2NlZHVyZXMsIHRoZSBkb2N1bWVudCBkZXBpY3RzIGVhY2ggc3RlcCBiYXNlZCBvbiBzaW1wbGUgYW5kIGNvbW1lbnRlZCBSIGNvZGUgcmFuZ2luZyBmcm9tIGRhdGEgcmVhZGluZyB0byBkYXRhIG1lcmdpbmcsIGNsZWFuaW5nLCBhbmQgY2VudGVyaW5nLCB1cCB0byBwc3ljaG9tZXRyaWMgYW5hbHlzZXMgYW5kIGNvbXB1dGF0aW9uIG9mIHRoZSBjb21wb3NpdGUgc2NvcmVzLiBUaGVuLCB0aGUgZG9jdW1lbnQgaW5jbHVkZSBhIGZldyBleGFtcGxlcyBvZiBkZXNjcmlwdGl2ZSBhbmQgaW5mZXJlbnRpYWwgbXVsdGlsZXZlbCBhbmFseXNlcyB0aGF0IGNhbiBiZSBhcHBsaWVkIHRvIGludmVzdGlnYXRlIHRoZSBqb2IgZGVtYW5kLWNvbnRyb2wgaHlwb3RoZXNlcyAoW0thcmFzZWssIDE5NzldKCNyZWYpKSBmcm9tIHRoZSBwcmUtcHJvY2Vzc2VkIGRhdGFzZXQuIEZpbmFsbHksIHRoZSBkb2N1bWVudCBlbmRzIHdpdGggYW4gaWxsdXN0cmF0aW9uIG9mIGhvdyBhIG11bHRpdmVyc2UgZGF0YSBtYW5pcHVsYXRpb24gYXBwcm9hY2ggY2FuIGJlIGFwcGxpZWQgdG8gZXZhbHVhdGUgdGhlIHJvYnVzdG5lc3Mgb2YgdGhlIG9idGFpbmVkIGZpbmRpbmdzLg0KDQpUaGUgZG9jdW1lbnQgYW5kIHRoZSBpbmNsdWRlZCBjb2RlIGFyZSBiYXNlZCBvbiBSIDQuNC4xLCBhcyByZXR1cm5lZCBieSB0aGUgYFIudmVyc2lvbmAgY29tbWFuZCBiZWxvdy4gVG8gZ2V0IHN0YXJ0IHdpdGggUiwgd2UgcmVjb21tZW5kIFtLYWJhY29mZiAoMjAyMildKCNyZWYpLCBbRWluc3BydWNoICgyMDIyKV0oI3JlZiksIGFuZCBbV2lja2hhbSBldCBhbC4gKDIwMjMpXSgjcmVmKSAoZnJlZWx5IGF2YWlsYWJsZSBhdCBbdGhpcyBsaW5rXShodHRwczovL3I0ZHMuaGFkbGV5Lm56L2luZGV4Lmh0bWwpKS4gU3BlY2lmaWNhbGx5IGZvciBJL08gcHN5Y2hvbG9naXN0cywgd2UgYWxzbyBzdWdnZXN0IHRocmVlIGJvb2tzIG9uIGh1bWFuIHJlc291cmNlcyBhbmFseXRpY3MgaW4gUjogW0NhdWdobGluICgyMDIzKV0oI3JlZikgKGZyZWVseSBhdmFpbGFibGUgYXQgW3RoaXMgbGlua10oaHR0cHM6Ly9yZm9yaHIuY29tL2luZGV4Lmh0bWwjaHJhZ3Jvd3RoKSksIFtNY051bHR5ICgyMDIyKV0oI3JlZikgKGZyZWVseSBhdmFpbGFibGUgYXQgW3RoaXMgbGlua10oaHR0cHM6Ly9wZW9wbGVhbmFseXRpY3MtcmVncmVzc2lvbi1ib29rLm9yZy9pbmRleC5odG1sKSksIGFuZCBbU3RhcmJ1Y2sgKDIwMjMpXSgjcmVmKSAoZnJlZWx5IGF2YWlsYWJsZSBhdCBbdGhpcyBsaW5rXShodHRwczovL2xpbmsuc3ByaW5nZXIuY29tL2Jvb2svMTAuMTAwNy85NzgtMy0wMzEtMjg2NzQtMikpLg0KYGBge3IgIH0NClIudmVyc2lvbg0KYGBgDQoNCk5vdGUgdGhhdCBhbnkgdGV4dCBwcmVjZWRlZCBieSB0aGUgYCNgIHN5bWJvbCBpcyBhIGNvbW1lbnQgdGhhdCBpcyBub3QgY29uc2lkZXJlZCBieSBSLg0KYGBge3IgIH0NCiMgdGhpcyBpcyBhIGNvbW1lbnQNCmBgYA0KDQpIZXJlLCB3ZSByZW1vdmUgYWxsIG9iamVjdHMgZnJvbSB0aGUgUiBnbG9iYWwgZW52aXJvbm1lbnQgdG8gZW5zdXJlIHRoYXQgd2Ugc3RhcnQgZnJvbSBzY3JhdGNoLg0KYGBge3IgIH0NCiMgcmVtb3ZpbmcgYWxsIG9iamV0cyBmcm9tIHRoZSB3b3Jrc3BhY2UNCnJtKGxpc3Q9bHMoKSkNCmBgYA0KDQpUaGUgZm9sbG93aW5nIFIgcGFja2FnZXMgYXJlIHVzZWQgaW4gdGhpcyBkb2N1bWVudCAoc2VlIFtSZWZlcmVuY2VzXSgjcmVmKSBzZWN0aW9uKToNCmBgYHtyICB9DQojIHJlcXVpcmVkIHBhY2thZ2VzDQpwYWNrYWdlcyA8LSBjKCJvc2ZyIiwiYmlyayIsInBseXIiLCJwc3ljaCIsImxhdmFhbiIsImxtZTQiLCJzalBsb3QiLCJnZ3Bsb3QyIiwiZ3JpZEV4dHJhIiwidGlkeXZlcnNlIikNCmBgYA0KDQpgYGB7ciAgZWNobz1GQUxTRX0NCiMgdGhpcyBpcyBqdXN0IHRvIGdlbmVyYXRlIHBhY2thZ2VzIHJlZmVyZW5jZXMgYXQgdGhlIGVuZCBvZiB0aGUgZG9jdW1lbnQNCmtuaXRyOjp3cml0ZV9iaWIoYygucGFja2FnZXMoKSwgcGFja2FnZXMpLCJwYWNrYWdlcy5iaWIiKQ0KYGBgDQoNCmBgYHtyICBldmFsPUZBTFNFfQ0KIyBydW4gdGhpcyBsaW5lIHRvIGluc3RhbGwgYWxsIG1pc3NpbmcgcGFja2FnZXMNCnhmdW46OnBrZ19hdHRhY2gyKHBhY2thZ2VzLCBtZXNzYWdlID0gRkFMU0UpOyBybShsaXN0PWxzKCkpDQpgYGANCg0KTW9yZW92ZXIsIHNpbmNlIHdlIHdvcmsgd2l0aCBleGlzdGluZyBkYXRhIGF2YWlsYWJsZSBmcm9tIHRoZSBPU0YgcmVwb3NpdG9yeSBhdCA8aHR0cHM6Ly9kb2kub3JnLzEwLjE3NjA1L09TRi5JTy84N0E5UD4sIHdlIHVzZSB0aGUgYG9zZnJgIHBhY2thZ2UgdG8gZG93bmxvYWQgdGhlIGBTNV9wcm9jZXNzZWREYXRhYCBmb2xkZXIgaW5jbHVkaW5nIHRoZSBkYXRhc2V0cy4gTm90ZSB0aGF0IHRoZSBmb2xkZXIgaXMgZG93bmxvYWRlZCBpbiB0aGUgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeSB1c2VkIGJ5IFIsIHdoaWNoIGNhbiBiZSB2aXN1YWxpemVkIGJ5IHJ1bm5pbmcgdGhlIGBnZXR3ZCgpYCBjb21tYW5kLg0KYGBge3IgIGV2YWw9RkFMU0V9DQojIGRvd25sb2FkIGRhdGFzZXQgZnJvbSBPU0YgcmVwb3NpdG9yeQ0KbGlicmFyeShvc2ZyKQ0KcmVwbyA8LSAjIHJldHJpZXZpbmcgcmVwb3NpdG9yeQ0KICBvc2ZfcmV0cmlldmVfbm9kZSgiaHR0cHM6Ly9kb2kub3JnLzEwLjE3NjA1L09TRi5JTy84N0E5UCIpIA0Kb3NmX2Rvd25sb2FkKG9zZl9sc19maWxlcyhyZXBvKVsxLCBdLCAjIGRvd25sb2FkaW5nIGRhdGFzZXRzIGludG8gdGhlIGN1cnJlbnQgd29ya2luZyBkaXJlY3RvcnkNCiAgICAgICAgICAgICBjb25mbGljdHM9Im92ZXJ3cml0ZSIpIA0KYGBgDQoNCjxicj4NCg0KIyAxLiBEYXRhIG1hbmlwdWxhdGlvbiBzdGVwcyB7I3N0ZXBzfQ0KDQojIyAxLjEuIERhdGEgcmVhZGluZw0KDQpGaXJzdCwgd2UgcmVhZCB0aGUgYGlsZGAgZGF0YXNldCBpbmNsdWRpbmcgdGltZS12YXJ5aW5nIHZhcmlhYmxlcyBzdWNoIGFzIHRhc2sgZGVtYW5kcyBhbmQgdGFzayBjb250cm9sLCBhbmQgdGhlIHByZWxpbWluYXJ5IHF1ZXN0aW9ubmFpcmUgYHByZWxxc2AgZGF0YXNldCBpbmNsdWRpbmcgdGltZS1pbnZhcmlhbnQgdmFyaWFibGVzIHN1Y2ggYXMgcGFydGljaXBhbnRzJyBhZ2UgYW5kIGdlbmRlci4gQm90aCBkYXRhc2V0cyB3ZXJlIHJlY29yZGVkIHVzaW5nIHRoZSBgQ1NWYCBmb3JtYXQgYW5kIGNhbiBiZSByZWFkIHdpdGggdGhlIGByZWFkLmNzdigpYCBmdW5jdGlvbi4gTm90ZSB0aGF0IHdlIHNldCBgc3RyaW5nc0FzRmFjdG9ycyA9IFRSVUVgIHNvIHRoYXQgY2hhcmFjdGVyIHN0cmluZyBjb2x1bW5zIGFyZSBjb25zaWRlcmVkIGFzIGNhdGVnb3JpY2FsIHZhcmlhYmxlcy4NCmBgYHtyICB9DQojIHJlYWRpbmcgSUxEIGRhdGFzZXQNCmlsZCA8LSByZWFkLmNzdigiUzVfcHJvY2Vzc2VkRGF0YS9FU01fcHJvY2Vzc2VkLmNzdiIsDQogICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IFRSVUUpDQoNCiMgcmVhZGluZyBwcmVsaW1pbmFyeSBxdWVzdGlvbm5haXJlDQpwcmVscXMgPC0gcmVhZC5jc3YoIlM1X3Byb2Nlc3NlZERhdGEvUkVUUk9fcHJvY2Vzc2VkLmNzdiIsIA0KICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBUUlVFKSANCmBgYA0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1pbmZvIj4NCjxkZXRhaWxzPjxzdW1tYXJ5PipXaGF0IGlmIHRoZSBkYXRhIGNvbGxlY3Rpb24gcGxhdGZvcm0gZXhwb3J0cyBhIHNlcGFyYXRlIGZpbGUgZm9yIGVhY2ggcGFydGljaXBhbnQ/KiA8YnI+IENsaWNrIGhlcmUgdG8gdmlldyBhZGRpdGlvbmFsIGNvZGU8L3N1bW1hcnk+DQo8cD4NCg0KPGJyPg0KDQpJbiBvdXIgY2FzZSwgd2UgZG8gbm90IG5lZWQgdG8gbWVyZ2UgbXVsdGlwbGUgZGF0YSBmaWxlcyBiZWNhdXNlIHRoZSBkYXRhc2V0IGhhcyBhbHJlYWR5IGJlZW4gdW5pZmllZCAoW3NlZSBmdWxsIHJlcG9ydF0oaHR0cHM6Ly9sdWNhLW1lbmdoaW5pLmdpdGh1Yi5pby9FU01zY2FsZXMtd29ya3BsYWNlU3RyZXNzL1MyX2RhdGFQcm9jZXNzaW5nL1MyX2RhdGFQcm9jZXNzaW5nX3JlcG9ydC5odG1sKSkuIFlldCwgc2luY2Ugc29tZSBwbGF0Zm9ybXMgZXhwb3J0IHNlcGFyYXRlIGZpbGVzIGdyb3VwaW5nIGRhdGEgYnkgcGFydGljaXBhbnQsIGl0IGlzIHdvcnRoIGlsbHVzdHJhdGluZyBob3cgdGhlc2UgY2FuIGJlIG1lcmdlZCBpbnRvIGEgc2luZ2xlIHVuaWZpZWQgZGF0YXNldC4gRm9yIGRvaW5nIHRoaXMsIHdlIGZpcnN0bHkgc3BsaXQgdGhlIGBpbGRgIGRhdGFzZXQgaW50byBzZXBhcmF0ZSBkYXRhIGZpbGVzIHRoYXQgd2Ugc2F2ZSBiYXNlZCBvbiBwYXJ0aWNpcGFudCBpZGVudGlmaWVycyAoaS5lLiwgcGFydGljaXBhbnRzIGBJRGAgYXJlIG5vdCByZXBvcnRlZCBpbiBhIGRhdGFzZXQgY29sdW1uIGJ1dCBlYWNoIGZpbGUgaXMgbmFtZWQgd2l0aCB0aGUgY29ycmVzcG9uZGluZyBwYXJ0aWNpcGFudCBpZGVudGlmaWVyKS4gVGhlbiwgd2UgdXNlIHRoZSBgbGlzdC5maWxlc2AgZnVuY3Rpb24gdG8gbGlzdCB0aGUgbmFtZXMgb2YsIGFuZCB0aGUgcGF0aHMgdG8sIGVhY2ggZGF0YSBmaWxlLiBTZWNvbmQsIHdlIGNyZWF0ZSBhbiBlbXB0eSBkYXRhLmZyYW1lIGBpbGQyYCB3aXRoIHplcm8gcm93IGFuZCB0aGUgc2FtZSBudW1iZXIgb2YgY29sdW1uIHRoYW4gdGhlIG9yaWdpbmFsIGBpbGRgIGRhdGFzZXQuIEZpbmFsbHksIHdlIHVzZSBhIGZvci1sb29wIHRvIHJlYWQgZWFjaCBkYXRhIGZpbGUsIHJlY3JlYXRlIHRoZSBgSURgIHZhcmlhYmxlIGJhc2VkIG9uIHRoZSBmaWxlIG5hbWUsIGFuZCBhZGQgdGhlIG5ldyBkYXRhIHRvIHRoZSBlbXB0eSBkYXRhc2V0IGBpbGQyYCB1c2luZyB0aGUgYHJiaW5kYCBmdW5jdGlvbi4gV2UgY2FuIHNlZSB0aGF0IHRoZSByZXN1bHRpbmcgZGF0YXNldCBjb3JyZXNwb25kcyB0byB0aGUgb3JpZ2luYWwgYGlsZGAgZGF0YXNldC4NCmBgYHtyICBldmFsPUZBTFNFfQ0KIyBzYXZpbmcgZGF0YSBzZXBhcmF0ZWx5IGJ5IHBhcnRpY2lwYW50IGFmdGVyIGNyZWF0aW5nIHRoZSAiZGF0YS1zcGxpdCIgZm9sZGVyDQpkaXIuY3JlYXRlKCJkYXRhLXNwbGl0IikgIyBjcmVhdGluZyB0aGUgImRhdGEtc3BsaXQiIGZvbGRlciBpbnNpZGUgdGhlIHdvcmtpbmcgZGlyZWN0b3J5DQpmb3IoaWQgaW4gbGV2ZWxzKGFzLmZhY3RvcihpbGQkSUQpKSl7ICMgc2F2aW5nIGRhdGEgd2l0aGluIHRoZSAiZGF0YS1zcGxpdCIgZm9sZGVyDQogIHdyaXRlLmNzdihzdWJzZXQoaWxkW2lsZCRJRD09aWQsXSxzZWxlY3Q9LUlEKSxwYXN0ZTAoImRhdGEtc3BsaXQvIixpZCwiLmNzdiIpLA0KICAgICAgICAgICAgcm93Lm5hbWVzPUZBTFNFKSB9DQojIG5vdGU6IHRoZSBjb2RlIGFib3ZlIGlzIGp1c3QgdG8gaWxsdXN0cmF0ZSB0aGlzIHByZWxpbWluYXJ5IHN0ZXANCmBgYA0KYGBge3IgIH0NCiMgc2VsZWN0aW5nIHRoZSBuYW1lIG9mIHRoZSBmb2xkZXIgc3RvcmluZyB0aGUgZGF0YSBmaWxlcw0KZGF0YS5wYXRoIDwtICJkYXRhLXNwbGl0Ig0KDQojIGxpc3RpbmcgdGhlIGZpbGUgbmFtZXMgd2l0aGluIHRoZSBkYXRhLnBhdGggZm9sZGVyDQpmaWxlTmFtZXMgPC0gbGlzdC5maWxlcyhkYXRhLnBhdGgsZnVsbC5uYW1lcz1UUlVFKQ0KZmlsZU5hbWVzICMgc2hvd2luZyBmaWxlIG5hbWVzDQoNCiMgY3JlYXRpbmcgZW1wdHkgZGF0YS5mcmFtZSBpbGQyDQppbGQyIDwtIGRhdGEuZnJhbWUobWF0cml4KG5yb3c9MCxuY29sPTM3KSkNCg0KIyByZWFkaW5nIGFuZCBtZXJnaW5nIGRhdGEgZmlsZXMgaW50byBhIHVuaWZpZWQgZGF0YXNldCAnaWxkMicNCmZvcihmaWxlTmFtZSBpbiBmaWxlTmFtZXMpeyAjIGZvciBlYWNoIGZpbGUgaW5jbHVkZWQgaW4gdGhlIGRhdC5wYXRoIGZvbGRlci4uLg0KICBuZXdGaWxlIDwtIHJlYWQuY3N2KGZpbGVOYW1lKSAjIHJlYWRpbmcgZmlsZQ0KICBuZXdGaWxlJElEIDwtIGdzdWIoImRhdGEtc3BsaXQvIiwiIiwgIyBleHRyYWN0aW5nIHBhcnRpY2lwYW50IElEIGZyb20gZmlsZSBuYW1lDQogICAgICAgICAgICAgICAgICAgICBnc3ViKCIuY3N2IiwiIixmaWxlTmFtZSkpDQogICMgYWRkaW5nIG5ldyBkYXRhIHRvIHRoZSBlbXB0eSBkYXRhLmZyYW1lICh0aGUgcm93IG5hbWVzIHNob3VsZCBiZSB0aGUgc2FtZSkNCiAgaWxkMiA8LSByYmluZChpbGQyLG5ld0ZpbGUpIH0gDQoNCiMgc2hvd2luZyB0aGUgdW5pZmllZCBkYXRhc2V0DQppbGQyWyxjKCJJRCIsY29sbmFtZXMoaWxkMilbMToobmNvbChpbGQpLTEpXSldDQoNCiMgc2hvd2luZyB0aGUgb3JpZ2luYWwgZGF0YXNldA0KaWxkDQpgYGANCg0KPC9wPg0KPC9kZXRhaWxzPg0KPC9kaXY+DQoNClRoZW4sIHdlIGlkZW50aWZ5IGFuZCBzZWxlY3QgdGhlIG1haW4gZGF0YSBjb2x1bW5zIG9mIGludGVyZXN0IGJ5IHVzaW5nIHNxdWFyZWQgYnJhY2tldHMgYFtyb3duYW1lcywgY29sbmFtZXNdYCBzdGFuZGluZyBmb3IgJ2RhdGEgc3Vic2V0Jy4gTm90ZSB0aGF0IHRoZSBuYW1lcyBvZiB0aGUgc2VsZWN0ZWQgY29sdW1ucyBzaG91bGQgYmUgd3JpdHRlbiB3aXRoaW4gcXVvdGVzIChlLmcuLCBgIklEImApIGFuZCBzaG91bGQgYmUgaW5jbHVkZWQgaW4gdGhlIGBjKClgIGZ1bmN0aW9uLCBzdGFuZGluZyBmb3IgJ2NvbWJpbmUnLiBPZiBub3RlLCB3aGlsZSB0aGUgYFJ1blRpbWVzdGFtcGAgYW5kIGBTdWJtaXNzaW9uVGltZXN0YW1wYCB2YXJpYWJsZXMgd2VyZSBuYW1lZCBieSB0aGUgc3VydmV5IHJlY29yZGluZyBzeXN0ZW0sIHRoZSByZW1haW5pbmcgdmFyaWFibGVzIHdlcmUgY2FyZWZ1bGx5IG5hbWVkIHRvIGlkZW50aWZ5IGl0ZW1zIGJlbG9uZ2luZyB0byB0aGUgc2FtZSBzY2FsZSAoZS5nLiwgaXRlbXMgc3RhcnRpbmcgd2l0aCAiZCIgd2VyZSBpbmNsdWRlZCBpbiB0aGUgVGFzayBEZW1hbmQgU2NhbGUsIHdoZXJlYXMgaXRlbXMgc3RhcnRpbmcgd2l0aCAiYyIgd2VyZSBpbmNsdWRlZCBpbiB0aGUgVGFzayBDb250cm9sIFNjYWxlKS4gQXMgaGlnaGxpZ2h0ZWQgaW4gdGhlIG1haW4gbWFudXNjcmlwdCwgc3RyYXRlZ2ljYWxseSBuYW1pbmcgdGhlIHZhcmlhYmxlcyBpcyBjcml0aWNhbCB0byBwcmV2ZW50IG1pc3Rha2VzIGluIHRoZSBmb2xsb3dpbmcgc3RlcHMgYW5kIGltcHJvdmUgdGhlIGVmZmVjdGl2ZW5lc3MgYW5kIHRyYW5zcGFyZW5jeSBvZiB0aGUgZGF0YSBhbmFseXNpcyBzY3JpcHRzLg0KYGBge3IgIH0NCiMgc2VsZWN0aW5nIGNvbHVtbnMgb2YgaW50ZXJlc3QgZnJvbSBJTEQgZGF0YXNldA0KaWxkIDwtIGlsZFssYygiSUQiLCAjIHBhcnRpY2lwYW50IGlkZW50aWZpZXINCiAgICAgICAgICAgICAgIlJ1blRpbWVzdGFtcCIsIlN1Ym1pc3Npb25UaW1lc3RhbXAiLCAjIHRlbXBvcmFsIGNvb3JkaW5hdGVzDQogICAgICAgICAgICAgICJkMSIsImQyIiwiZDMiLCJkNCIsICMgdGFzayBkZW1hbmRzIGl0ZW1zDQogICAgICAgICAgICAgICJjMSIsImMyIiwiYzMiLCAjIHRhc2sgY29udHJvbCBpdGVtcw0KICAgICAgICAgICAgICAidjEiLCJ2MiIsInYzIildICMgbmVnYXRpdmUgdmFsZW5jZSBpdGVtcw0KDQojIHNlbGVjdGluZyBjb2x1bW5zIG9mIGludGVyZXN0IGZyb20gcHJlbGltaW5hcnkgcXVlc3Rpb25uYWlyZSBkYXRhc2V0DQpwcmVscXMgPC0gcHJlbHFzWyxjKCJJRCIsICMgcGFydGljaXBhbnQgaWRlbnRpZmllcg0KICAgICAgICAgICAgICAgICAgICAiYWdlIiwiZ2VuZGVyIildICMgdGltZS1pbnZhcmlhbnQgdmFyaWFibGVzDQpgYGANCg0KRmluYWxseSwgd2UgdGFrZSBhIGZpcnN0IGxvb2sgYXQgYm90aCBkYXRhc2V0cyBhbmQgdGhlIGluY2x1ZGVkIG51bWJlciBvZiBwYXJ0aWNpcGFudHMgYW5kIG9ic2VydmF0aW9ucy4gV2UgY2FuIHNlZSB0aGF0IGJvdGggZGF0YXNldHMgaW5jbHVkZSBhIHRvdGFsIG9mIGByIG5sZXZlbHMoaWxkJElEKWAgcGFydGljaXBhbnRzLCB3aXRoIHRoZSBgaWxkYCBkYXRhc2V0IGluY2x1ZGluZyBhIHRvdGFsIG9mIGByIG5yb3coaWxkKWAgb2JzZXJ2YXRpb25zLg0KYGBge3IgIH0NCiMgSUxEIGRhdGFzZXQNCm5yb3coaWxkKSAjIG9yaWdpbmFsIG51bWJlciBvZiBvYnNlcnZhdGlvbnMNCm5sZXZlbHMoaWxkJElEKSAjIG9yaWdpbmFsIG51bWJlciBvZiBwYXJ0aWNpcGFudHMNCmhlYWQoaWxkKSAjIHNob3dpbmcgZmlyc3Qgc2l4IHJvd3Mgb2YgZGF0YQ0KDQojIHByZWxpbWluYXJ5IHF1ZXN0aW9ubmFpcmUgZGF0YXNldA0KbnJvdyhwcmVscXMpICMgb3JpZ2luYWwgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBhbmQgcGFydGljaXBhbnRzDQpoZWFkKHByZWxxcykgIyBzaG93aW5nIGZpcnN0IHNpeCByb3dzIG9mIGRhdGENCmBgYA0KDQo8YnI+DQoNCiMjIDEuMi4gVGVtcG9yYWwgc3luY2hyb25pemF0aW9uIHsudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQ0KDQpBcyBhIHNlY29uZCBzdGVwLCB3ZSBzeW5jaHJvbml6ZSBhbmQgdmVyaWZ5IHRoZSBjb3JyZWN0bmVzcyBvZiB0aGUgdGVtcG9yYWwgY29vcmRpbmF0ZXMgYXNzb2NpYXRlZCB3aXRoIGVhY2ggZGF0YSBwb2ludC4gSW4gb3VyIGNhc2UsIHRlbXBvcmFsIGNvb3JkaW5hdGVzIGFyZSBvbmx5IGF2YWlsYWJsZSBmb3IgdGhlIGBpbGRgIGRhdGFzZXQuIFdlIGNhbiB2ZXJpZnkgdGhlaXIgY29ycmVjdG5lc3MgYnkgZmlyc3RseSBjb252ZXJ0aW5nIHRoZW0gYXMgYFBPU0lYY3RgIChpLmUuLCB0aGUgdmFyaWFibGUgY2xhc3MgdXNlZCBieSBSIHRvIHdvcmsgd2l0aCBkYXRlcyBhbmQgdGltZXMpLCBieSBzcGxpdHRpbmcgYHRpbWVgIGFuZCBgZGF0ZWAgaW5mb3JtYXRpb24sIGFuZCBieSBjaGVja2luZyB3aGV0aGVyIHJlc3BvbnNlIHRpbWVzIGFyZSBjb25zaXN0ZW50IHdpdGggc2NoZWR1bGVkIHRpbWVzLiBOb3RlIHRoYXQgdGhlIGBhcy5QT1NJWGN0YCBmdW5jdGlvbiByZXF1aXJlcyBzcGVjaWZ5aW5nIHRoZSBkYXRlLXRpbWUgZm9ybWF0IG9mIHRoZSBpbnB1dHRlZCBjaGFyYWN0ZXIgc3RyaW5ncyB1c2luZyB0aGUgYGZvcm1hdGAgYXJndW1lbnQuIEZvciBpbnN0YW5jZSwgdGhlIGRhdGUgZm9ybWF0ICJgJVktJW0tJWRgIiBzdGFuZHMgZm9yIGRhdGVzIGV4cHJlc3NlZCBhcyAieWVhci1tb250aC1kYXkiLCByZXBvcnRpbmcgeWVhcnMgd2l0aCBjZW50dXJ5IChlLmcuLCAiYDIwMjVgIikgYW5kIG1vbnRocyBhbmQgZGF5cyBhcyBkZWNpbWFsIG51bWJlcnMgKGUuZy4sICIwMSIgZm9yIEphbnVhcnksIGFuZCAiMDIiIGZvciB0aGUgc2Vjb25kIGRheSBvZiB0aGUgbW9udGgpLCB3aGVyZWFzIHRoZSB0aW1lIGZvcm1hdCAiYCVIOiVNOiVTYCIgc3RhbmRzIGZvciB0aW1lcyBleHByZXNzZWQgYXMgImhvdXJzOm1pbnV0ZXM6c2Vjb25kcyIgYXMgZGVjaW1hbCBudW1iZXJzIChmb3IgbW9yZSBkZXRhaWxzLCBydW4gYD9zdHJwdGltZWAgaW4gdGhlIGNvbnNvbGUpLg0KYGBge3IgIH0NCiMgcmVzcG9uc2UgaW5pdGlhdGlvbiBhbmQgc3VibWlzc2lvbiB0aW1lIGFzIFBPU0lYY3QNCmlsZCRSdW5UaW1lc3RhbXAgPC0gYXMuUE9TSVhjdChpbGQkUnVuVGltZXN0YW1wLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JtYXQgPSAiJVktJW0tJWQgJUg6JU06JVMiKQ0KaWxkJFN1Ym1pc3Npb25UaW1lc3RhbXAgPC0gYXMuUE9TSVhjdChpbGQkU3VibWlzc2lvblRpbWVzdGFtcCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1hdCA9ICIlWS0lbS0lZCAlSDolTTolUyIpDQoNCiMgcmVzcG9uc2UgaW5pdGlhdGlvbiBkYXRlIGFzIERhdGUgd2l0aG91dCB0aW1lDQppbGQkZGF0ZSA8LSBhcy5EYXRlKHN1YnN0cihpbGQkUnVuVGltZXN0YW1wLDEsMTApLA0KICAgICAgICAgICAgICAgICAgICBmb3JtYXQ9IiVZLSVtLSVkIikNCg0KIyByZXNwb25zZSBpbml0aWF0aW9uIHRpbWUgYXMgUE9TSVhjdCB3aXRob3V0IGRhdGUNCmlsZCR0aW1lIDwtIGFzLlBPU0lYY3Qoc3Vic3RyKGlsZCRSdW5UaW1lc3RhbXAsMTIsMTkpLCANCiAgICAgICAgICAgICAgICAgICAgICAgZm9ybWF0ID0gIiVIOiVNOiVTIikNCmBgYA0KDQpIZXJlLCB3ZSBwbG90IHRoZSBoaXN0b2dyYW1zIG9mIHRoZSByZXN1bHRpbmcgYGRhdGVgIGFuZCBgdGltZWAgdmFyaWFibGVzIHRvIHZlcmlmeSB0aGUgZnJlcXVlbmN5IG9mIHJlc3BvbnNlcyBpbml0aWF0ZWQgaW5zaWRlIGFuZCBvdXRzaWRlIHRoZSBzdHVkeSB0ZW1wb3JhbCBmcmFtZXMuIE5vdGUgdGhhdCB3aXRoIG9iamVjdHMgb2YgY2xhc3MgYFBPU0lYY3RgIHRoZSBmdW5jdGlvbiBgaGlzdGAgKGZvciBwbG90dGluZyBoaXN0b2dyYW1zKSByZXF1aXJlcyBzcGVjaWZ5aW5nIHRoZSB0ZW1wb3JhbCBpbnRlcnZhbHMgdG8gYmUgcGxvdHRlZCB3aXRoIHRoZSBhcmd1bWVudCBgYnJlYWtzYCAoZm9yIG1vcmUgZGV0YWlscywgcnVuIGA/aGlzdC5QT1NJWHRgIGluIHRoZSBjb25zb2xlKSwgd2hpY2ggd2Ugc2V0IHRvIGAibW9udGhzImAgYW5kIGAiaG91cnMiYCBmb3IgcmVzcG9uc2UgZGF0ZXMgYW5kIHRpbWVzLCByZXNwZWN0aXZlbHkuIFdlIGNhbiBzZWUgdGhhdCByZXNwb25zZSBpbml0aWF0aW9uIGRhdGVzIGFuZCB0aW1lcyBhcmUgY29tcGF0aWJsZSB3aXRoIHRoZSBkYXRhIGNvbGxlY3Rpb24gcGVyaW9kIChpLmUuLCBPY3RvYmVyIDIwMTggLSBPY3RvYmVyIDIwMTkpIGFuZCB3aXRoIHRoZSBzY2hlZHVsZWQgRVNNIHRpbWluZyAoaS5lLiwgYmV0d2VlbiA5OjE1IEFNIGFuZCA2OjE1IFBNKSwgcmVzcGVjdGl2ZWx5LiBBIGZldyBjYXNlcyAoJG4kID0gMjIpIGFyZSBzbGlnaHRseSBvdXRzaWRlIHRoZSBzY2hlZHVsZWQgdGltZSBpbnRlcnZhbHMsIGJ1dCB0aGVzZSBtaWdodCBiZSBkdWUgdG8gdmFyaWFiaWxpdHkgaW4gdGVtcG9yYWwgc3luY2hyb25pemF0aW9uIGFjcm9zcyBkZXZpY2VzLCBzbyB3ZSBrZWVwIHRoZW0uDQpgYGB7ciAgfQ0KIyBwbG90dGluZyBkYXRlIGFuZCB0aW1lDQpwYXIobWZyb3c9YygyLDEpKSAjIHRoaXMgaXMgdG8gaGF2ZSAyIHBsb3RzIGluIHRoZSBzYW1lIHBhbmVsIA0KaGlzdChpbGQkZGF0ZSxicmVha3M9Im1vbnRocyIpICMgcGxvdHRpbmcgZGF0ZSBmcmVxdWVuY2llcyBtb250aC1ieS1tb250aA0KaGlzdChpbGQkdGltZSxicmVha3M9ImhvdXJzIikgIyBwbG90dGluZyB0aW1lIGZyZXF1ZW5jaWVzIGhvdXItYnktaG91cg0KDQojIG51bWJlciBvZiBjYXNlcyB3aXRoIHRpbWUgb3V0c2lkZSB0aGUgc2NoZWR1bGVkIGludGVydmFscw0KbnJvdyhpbGRbIWlzLm5hKGlsZCR0aW1lKSAmIA0KICAgICAgICAgICAoaWxkJHRpbWU8YXMuUE9TSVhjdCgiMDk6MTU6MDAiLCBmb3JtYXQgPSAiJUg6JU06JVMiKSB8IA0KICAgICAgICAgICAgICBpbGQkdGltZT5hcy5QT1NJWGN0KCIxODozMDowMCIsIGZvcm1hdCA9ICIlSDolTTolUyIpKSxdKQ0KYGBgDQoNCk1vcmVvdmVyLCB3ZSB1c2UgdGhlIHJlY29kZWQgdGVtcG9yYWwgY29vcmRpbmF0ZXMgdG8gY3JlYXRlIHRoZSB2YXJpYWJsZSBgZGF5YCwgaW5kZXhpbmcgdGhlIGRheSBvZiBwYXJ0aWNpcGF0aW9uIGZyb20gMSB0byAzLiBUaGlzIGlzIGRvbmUgYnkgdXNpbmcgYSBmb3ItbG9vcCB0aGF0IGNvbXBhcmVzIGVhY2ggcm93IGBpYCBpbiB0aGUgYGlsZGAgZGF0YXNldCB3aXRoIHRoZSBwcmV2aW91cyByb3cgYGktMWAuIFRoZW4sIHRoZSBgaWZgIGFuZCBgZWxzZWAgb3BlcmF0b3JzIGFyZSB1c2VkIHRvIGVzdGFibGlzaCB0aGUgdmFsdWUgb2YgdGhlIGBkYXlgIHZhcmlhYmxlcywgc3VjaCB0aGF0IGl0IGlzIGluY3JlYXNlZCBieSBvbmUgdW5pdCBldmVyeSB0aW1lIHRoYXQgdGhlIHZhbHVlIG9mIHRoZSBgZGF0ZWAgdmFyaWFibGUgaW5jcmVhc2VzIGJ5IG9uZSBkYXkgd2l0aGluIHRoZSBzYW1lIHBhcnRpY2lwYW50LCB3aGVyZWFzIGl0IGlzIHJlc2V0IHRvIHRoZSB2YWx1ZSAiMSIgZXZlcnkgdGltZSB0aGF0IHRoZSB2YWx1ZSBvZiB0aGUgdmFyaWFibGUgYElEYCBpcyBkaWZmZXJlbnQgdGhhbiB0aGUgdmFsdWUgcmVwb3J0ZWQgaW4gdGhlIHByZXZpb3VzIHJvdyAoaS5lLiwgZGF5IDEgZm9yIGEgZGlmZmVyZW50IHBhcnRpY2lwYW50KS4NCmBgYHtyICB9DQojIGNyZWF0aW5nIGRheSAoaS5lLiwgZGF5IG9mIHBhcnRpY2lwYXRpb24gZnJvbSAxIHRvIDMpDQppbGQkZGF5IDwtIDEgIyBpbml0aWFsbHkgc2V0IGFzIDENCmZvcihpIGluIDI6bnJvdyhpbGQpKXsgIyBGT1IgZWFjaCByb3cgc3RhcnRpbmcgZnJvbSB0aGUgc2Vjb25kIG9uZS4uLg0KICBpZihpbGRbaSwiSUQiXSAhPSBpbGRbaS0xLCJJRCJdKXsgIyBJRiB0aGUgSUQgdmFsdWUgaXMgZGlmZmVyZW50IHRoYW4gdGhlIHByZXZpb3VzIHJvdy4uLg0KICAgIGlsZFtpLCJkYXkiXSA8LSAxICMgLi4ucmVzdGFydCBmcm9tIGRheSAxLg0KICAgIA0KICB9IGVsc2UgeyAgIyBJRiB0aGUgSUQgdmFsdWUgaXMgdGhlIHNhbWUgb2YgdGhlIHByZXZpb3VzIHJvdy4uLg0KICAgIGlmKCFpcy5uYShpbGRbaSwiZGF0ZSJdKSAmICMgQU5EIGJvdGggY3VycmVudCBhbmQgcHJldmlvdXMgZGF0ZSBhcmUgbm90IG1pc3NpbmcuLi4NCiAgICAgICAhaXMubmEoaWxkW2ktMSwiZGF0ZSJdKSAmIA0KICAgICAgIGFzLlBPU0lYbHQoaWxkW2ksImRhdGUiXSkkd2RheSAhPSAjIEFORCB0aGUgZGF0ZSB2YWx1ZSBpcyBkaWZmZXJlbnQgdGhhbiB0aGUgcHJldmlvdXMgcm93Li4uDQogICAgICAgICBhcy5QT1NJWGx0KGlsZFtpLTEsImRhdGUiXSkkd2RheSl7DQogICAgICBpbGRbaSwiZGF5Il0gPC0gaWxkW2ktMSwiZGF5Il0gKyAxICMgLi4uYWRkIDEgZGF5Lg0KICAgICAgDQogICAgfSBlbHNleyAjIElGIHNhbWUgSUQgdmFsdWUgYnV0IHRoZSBkYXRlIHZhbHVlIGlzIHRoZSBzYW1lIHRoYW4gdGhlIHByZXZpb3VzIHJvdy4uLg0KICAgICAgICBpbGRbaSwiZGF5Il0gPC0gaWxkW2ktMSwiZGF5Il0gIyAuLi5rZWVwIHRoZSBzYW1lIGRheSB0aGFuIHRoZSBwcmV2aW91cyByb3cuDQogICAgICAgIH19fQ0KDQojIHNhbml0eSBjaGVjazogZGF5IGNhbiBvbmx5IHRha2UgdmFsdWUgMSwgMiwgb3IgMyAob2spDQp0YWJsZShpbGQkZGF5KSANCmBgYA0KDQpOb3RlIHRoYXQgdGhlIGBkYXlgIHZhcmlhYmxlIGNyZWF0ZWQgYWJvdmUgaXMgb25seSB1c2VkIHRvIGlkZW50aWZ5IHRoZSBvYnNlcnZhdGlvbnMgYXNzb2NpYXRlZCB3aXRoIHRoZSBzYW1lIHBhcnRpY2lwYW50LWJ5LWRheSBjbHVzdGVyLCBidXQgaXQgY2Fubm90IGJlIHVzZWQgdG8gb3BlcmF0aW9uYWxpemUgdGVtcG9yYWwgZGlzdGFuY2VzIGFzIGl0IGRvZXMgbm90IGltcGx5IGVxdWlkaXN0YW50IGludGVydmFscy4gSW5kZWVkLCBwYXJ0aWNpcGFudHMgd2VyZSBhbGxvd2VkIHRvIGZyZWVseSBjaG9vc2Ugd2hldGhlciBzdGFydGluZyBvbiBNb25kYXksIFdlZG5lc2RheSwgb3IgRnJpZGF5LCBpbXBseWluZyB0aGF0IHRoZSBkaXN0YW5jZSBiZXR3ZWVuIGRheSAxIGFuZCBkYXkgMiBjYW4gYmUgZXF1YWwgdG8gMiBkYXlzIGZvciBzb21lIHBhcnRpY2lwYW50cyAoaS5lLiwgZnJvbSBNb25kYXkgdG8gV2VkbmVzZGF5IG9yIGZyb20gV2VkbmVzZGF5IHRvIEZyaWRheSkgYW5kIDMgZGF5cyBmb3Igc29tZSBvdGhlciBwYXJ0aWNpcGFudHMgKGkuZS4sIGZyb20gRnJpZGF5IHRvIE1vbmRheSkuIFRvIGdldCBhIHZhcmlhYmxlIHRoYXQgaW5kZXhlcyB0aGUgZGF5IG9mIHRoZSB3ZWVrIGJ5IGFjY291bnRpbmcgZm9yIHRoZSBhY3R1YWwgdGVtcG9yYWwgZGlzdGFuY2UgYmV0d2VlbiBkYXlzIChpLmUuLCBpbXBseWluZyBlcXVpZGlzdGFudCBpbnRlcnZhbHMpLCBpdCBpcyBwb3NzaWJsZSB0byB1c2UgdGhlIGBhcy5QT1NJWGx0YCBmdW5jdGlvbiBieSBleHRyYWN0aW5nIHRoZSB3ZWVrZGF5IHdpdGggdGhlIGAkd2RheWAgc3ludGF4LiBUaGlzIHJldHVybnMgdGhlIHdlZWtkYXkgbnVtYmVyIGZyb20gMCAoU3VuZGF5KSB0byA2IChTYXR1cmRheSkuIEluIG91ciBjYXNlLCBpdCBjYW4gb25seSBnZXQgdmFsdWVzIDEgPSBNb25kYXksIDMgPSBXZWRuZXNkYXksIG9yIDUgPSBGcmlkYXkuDQpgYGB7ciB9DQpkYXRhLmZyYW1lKElEID0gaWxkJElELCAjIHBhcnRpY2lwYW50IElEDQogICAgICAgICAgIFJ1blRpbWVzdGFtcCA9IGlsZCRSdW5UaW1lc3RhbXAsICMgb3JpZ2luYWwgZGF0ZS10aW1lIHZhcmlhYmxlDQogICAgICAgICAgIGRheSA9IGlsZCRkYXksICMgcGFydGljaXBhbnQtYnktZGF5IGluZGljYXRvciBjcmVhdGVkIGFib3ZlDQogICAgICAgICAgIHdkYXkgPSBhcy5QT1NJWGx0KGlsZCRSdW5UaW1lc3RhbXApJHdkYXkpICMgZGF5IG9mIHdlZWsNCmBgYA0KDQpGaW5hbGx5LCB3ZSB1c2UgdGhlIHNjaGVkdWxlZCB0aW1lc3RhbXBzIHRvIGNyZWF0ZSB0aGUgdmFyaWFibGUgYGJlZXBgLCBpbmRleGluZyB0aGUgbWVhc3VyZW1lbnQgb2NjYXNpb24gd2l0aGluIGVhY2ggZGF5LCBmcm9tIDEgdG8gNy4gVG8gYWNjb3VudCBmb3IgcG90ZW50aWFsIHZhcmlhYmlsaXR5IGluIGRldmljZSB0ZW1wb3JhbCBzeW5jaHJvbml6YXRpb24sIDEwIG1pbnV0ZXMgYXJlIHN1YnRyYWN0ZWQgZnJvbSBlYWNoIGxvd2VyIHRpbWVzdGFtcCBhbmQgYWRkZWQgdG8gZWFjaCB1cHBlciB0aW1lc3RhbXAsIHJlc3BlY3RpdmVseS4NCmBgYHtyIG1lc3NhZ2U9RkFMU0V9DQojIGxpc3RpbmcgbWluaW11bSwgY2VudHJhbCwgYW5kIG1heGltdW0gc2NoZWR1bGVkIHRpbWUgZm9yIGVhY2ggdGltZSBwb2ludA0KdGltZXMgPC0gbGlzdChjKCIwOToxNTowMCIsIjA5OjMwOjAwIiwiMTA6MTU6MDAiKSwgIyBiZWVwIDENCiAgICAgICAgICAgICAgYygiMTA6MjA6MDAiLCIxMDozMDowMCIsIjEwOjQwOjAwIiksICMgYmVlcCAyDQogICAgICAgICAgICAgIGMoIjExOjUwOjAwIiwiMTI6MDA6MDAiLCIxMjoxMDowMCIpLCAjIGJlZXAgMw0KICAgICAgICAgICAgICBjKCIxMzoyMDowMCIsIjEzOjMwOjAwIiwiMTM6NDA6MDAiKSwgIyBiZWVwIDQNCiAgICAgICAgICAgICAgYygiMTQ6NTA6MDAiLCIxNTowMDowMCIsIjE1OjEwOjAwIiksICMgYmVlcCA1DQogICAgICAgICAgICAgIGMoIjE2OjIwOjAwIiwiMTY6MzA6MDAiLCIxNjo0MDowMCIpLCAjIGJlZXAgNg0KICAgICAgICAgICAgICBjKCIxNzo1MDowMCIsIjE4OjAwOjAwIiwiMTg6MTA6MDAiKSkgIyBiZWVwIDcNCg0KIyBjcmVhdGluZyBiZWVwIChpLmUuLCBzdXJ2ZXkgbnVtYmVyIHdpdGhpbiBkYXkgZnJvbSAxIHRvIDcpDQpmb3IoaSBpbiAxOmxlbmd0aCh0aW1lcykpeyAjIGFzc2lnbiBiZWVwIHZhbHVlIGRlcGVuZGluZyBvbiBlYWNoIGNvdXBsZSBvZiBtaW4tbWF4DQogIGlsZFshaXMubmEoaWxkJHRpbWUpICYgDQogICAgICAgIGlsZCR0aW1lID4gKGFzLlBPU0lYY3QodGltZXNbW2ldXVsxXSwgZm9ybWF0ID0gIiVIOiVNOiVTIikgLSAxMCo2MCkgJiANCiAgICAgICAgaWxkJHRpbWUgPCAoYXMuUE9TSVhjdCh0aW1lc1tbaV1dWzNdLCBmb3JtYXQgPSAiJUg6JU06JVMiKSArIDEwKjYwKSwiYmVlcCJdIDwtIGkgfQ0KDQojIGNvcnJlY3RpbmcgYmVlcCB3aGVuIHJlc3BvbnNlIHRpbWUgaXMgb3V0c2lkZSB0aGUgc2NoZWR1bGVkIGludGVydmFscw0KdGltZXMgPC0gYygiMDk6MzA6MDAiLCIxMDozMDowMCIsIjEyOjAwOjAwIiwiMTM6MzA6MDAiLCIxNTowMDowMCIsIjE2OjMwOjAwIiwiMTg6MDA6MDAiKSAjIHZlY3RvciBvZiBjZW50cmFsIHRpbWVzDQpmb3IoaSBpbiAxOm5yb3coaWxkKSl7ICMgd2hlbiB0aW1lIGlzIG91dHNpZGUgdGhlIHNjaGVkdWxlZCBpbnRlcnZhbHMsIHRoZSBjbG9zZXN0ICdiZWVwJyB2YWx1ZSBpcyBhc3NpZ25lZA0KICBpZihpcy5uYShpbGRbaSwiYmVlcCJdKSAmICFpcy5uYShpbGRbaSwidGltZSJdKSl7IHJlcXVpcmUoYmlyaykNCiAgICBpbGRbaSwiYmVlcCJdIDwtIHdoaWNoLmNsb3Nlc3QoYXMuUE9TSVhjdCh0aW1lcywgZm9ybWF0ID0gIiVIOiVNOiVTIiksIGlsZFtpLCJ0aW1lIl0pIH19DQp0YWJsZShpbGQkYmVlcCkgIyBzYW5pdHkgY2hlY2s6IGJlZXAgY2FuIG9ubHkgdGFrZSB2YWx1ZSAxLTcgKG9rKQ0KYGBgDQoNCkhlcmUsIHdlIHZpc3VhbGl6ZSB0aGUgb3JpZ2luYWwgYFJ1blRpbWVzdGFtcGAgdmFyaWFibGUgYWxvbmcgd2l0aCB0aGUgbmV3bHkgY3JlYXRlZCBgZGF5YCBhbmQgYGJlZXBgIHZhcmlhYmxlcy4NCmBgYHtyICB9DQppbGRbLGMoIklEIiwiUnVuVGltZXN0YW1wIiwiZGF5IiwiYmVlcCIpXQ0KYGBgDQoNCjxicj4NCg0KIyMgMS4zLiBEYXRhIGNsZWFuaW5nDQoNClRoaXJkLCB3ZSBpbnNwZWN0IGFuZCBmaWx0ZXIgY2FzZXMgb2YgbWlzc2luZyBhbmQgaW5hY2N1cmF0ZSBkYXRhLiBUbyB0cmFjayB0aGUgdG90YWwgbnVtYmVyIG9mIGV4Y2x1ZGVkIG9ic2VydmF0aW9ucyBhbmQgcGFydGljaXBhbnRzLCB3ZSBpbml0aWFsbHkgcmVjb3JkIHRoZSBvcmlnaW5hbCBzYW1wbGUgc2l6ZSBhdCBib3RoIGxldmVscy4NCmBgYHtyICB9DQojIG9yaWdpbmFsIG51bWJlciBvZiBvYnNlcnZhdGlvbnMNCm4xIDwtIG5yb3coaWxkKQ0KDQojIG9yaWdpbmFsIG51bWJlciBvZiBwYXJ0aWNpcGFudHMNCm4yIDwtIG5sZXZlbHMoaWxkJElEKQ0KYGBgDQoNCkV2ZW4gbW9yZSB3aXNlbHksIHdlIG1pZ2h0IHNhdmUgdGhlIG9yaWdpbmFsIGRhdGFzZXQocykgYmVmb3JlIGFwcGx5aW5nIGFueSBkYXRhIGNsZWFuaW5nIHByb2NlZHVyZSwgc28gdGhhdCBpZiBhbnkgZXJyb3Igb2NjdXJzIGluIHRoZSBwcm9jZXNzIHdlIGNhbiBzdGFydCBmcm9tIHRoaXMg4oCYY2hlY2twb2ludOKAmSByYXRoZXIgdGhhbiByZXN0YXJ0aW5nIGZyb20gdGhlIGJlZ2lubmluZy4gDQpgYGB7ciAgfQ0KIyBzYXZpbmcgZGF0YSBiZWZvcmUgY2xlYW5pbmcgaXQNCmlsZC5vcmlnaW5hbCA8LSBpbGQNCnByZWxxcy5vcmlnaW5hbCA8LSBwcmVscXMNCg0KIyAjIHJ1biB0aGVzZSBsaW5lcyB0byByZXN0YXJ0IGZyb20gdGhlIHJhdyBkYXRhDQojIGlsZCA8LSBpbGQub3JpZ2luYWwNCiMgcHJlbHFzIDwtIHByZWxxcy5vcmlnaW5hbA0KYGBgDQoNCjxicj4NCg0KIyMjIDEuMy4xLiBJbmNvbXBsZXRlIHJlc3BvbnNlcw0KDQpIZXJlLCB3ZSBpbnNwZWN0IGFuZCBmaWxlciB0aGUgbnVtYmVyIG9mIGNhc2VzIHdpdGggbWlzc2luZyB2YWx1ZXMgZm9yIHNvbWUgb3IgYWxsIHZhcmlhYmxlcyAoZS5nLiwgcG9zc2libHkgZHVlIHRvIGxhY2sgb2YgY29tcGxpYW5jZSBvciB0ZWNobmljYWwgaXNzdWVzIHdpdGggdGhlIG1vYmlsZSBhcHApLiBGaXJzdCwgd2UgcmVtb3ZlIGFueSBwYXJ0aWNpcGFudCB0aGF0IG9ubHkgcmVzcG9uZGVkIHRvIHRoZSBwcmVsaW1pbmFyeSBxdWVzdGlvbm5haXJlIGJ1dCBkaWQgbm90IHJlc3BvbmQgdG8gYW55IEVTTSBxdWVzdGlvbm5haXJlIChgciBucm93KGlsZFtpcy5uYShpbGQkUnVuVGltZXN0YW1wKSxdKWAsIGByIHJvdW5kKDEwMCpucm93KGlsZFtpcy5uYShpbGQkUnVuVGltZXN0YW1wKSxdKS9ucm93KGlsZCksMSlgJSksIGFuZCB2aWNlIHZlcnNhIChgciBucm93KHByZWxxc1tpcy5uYShwcmVscXMkYWdlKSB8IGlzLm5hKHByZWxxcyRnZW5kZXIpIHwgIXByZWxxcyRJRCVpbiVpbGQkSUQsXSlgLCBgciByb3VuZCgxMDAqbnJvdyhwcmVscXNbaXMubmEocHJlbHFzJGFnZSkgfCBpcy5uYShwcmVscXMkZ2VuZGVyKSB8ICFwcmVscXMkSUQlaW4laWxkJElELF0pL25yb3cocHJlbHFzKSwxKWAlKS4gTm90ZSB0aGF0IHRoZSBgJWluJWAgb3BlcmF0b3IgaXMgdXNlZCB0byB1cGRhdGUgZWFjaCBkYXRhc2V0IGJ5IG9ubHkgaW5jbHVkaW5nIHRoZSBgSURgIHZhbHVlcyB0aGF0IGFyZSBhbHNvIGluY2x1ZGVkIGluIHRoZSBvdGhlciBkYXRhc2V0LCBhbmQgdmljZSB2ZXJzYS4NCmBgYHtyICB9DQojIHJlbW92aW5nIHBhcnRpY2lwYW50cyB3aXRoIG5vIHJlc3BvbnNlIHRvIHRoZSBwcmVsaW1pbmFyeSBxdWVzdGlvbm5haXJlDQpwcmVscXMgPC0gcHJlbHFzWyFpcy5uYShwcmVscXMkYWdlKSAmICMgb25seSByZXRhaW5pbmcgcm93cyB3aXRoIG5vbi1taXNzaW5nIHZhbHVlcyB0byBhZ2UuLi4NCiAgICAgICAgICAgICAgICAgICAhaXMubmEocHJlbHFzJGdlbmRlciksXSAjIC4uLiBhbmQgZ2VuZGVyDQppbGQgPC0gaWxkW2lsZCRJRCAlaW4lIGFzLmNoYXJhY3RlcihwcmVscXMkSUQpLF0gIyB1cGRhdGluZyBpbGQgZGF0YXNldA0KDQojIHJlbW92aW5nIHBhcnRpY2lwYW50cyB3aXRoIG5vIHJlc3BvbnNlIHRvIGFueSBFU00gcXVlc3Rpb25uYWlyZQ0KaWxkIDwtIGlsZFshaXMubmEoaWxkJFJ1blRpbWVzdGFtcCksXSAjIG9ubHkgcmV0YWluaW5nIHJvd3Mgd2l0aCBub24tbWlzc2luZyB2YWx1ZXMgdG8gUnVuVGltZVNhbXANCnByZWxxcyA8LSBwcmVscXNbcHJlbHFzJElEICVpbiUgYXMuY2hhcmFjdGVyKGlsZCRJRCksXSAjIHVwZGF0aW5nIHByZWxxcyBkYXRhc2V0DQpgYGANCg0KVGhlbiwgd2UgZmlsdGVyIGFsbCByZXNwb25zZXMgdG8gdGhlIGZpcnN0IGBiZWVwYCBvZiBlYWNoIGRheSAoKm4qID0gYHIgbnJvdyhpbGRbIWlzLm5hKGlsZCRiZWVwKSAmIGlsZCRiZWVwPT0xLF0pYCwgYHIgcm91bmQoMTAwKm5yb3coaWxkWyFpcy5uYShpbGQkYmVlcCkgJiBpbGQkYmVlcD09MSxdKS9ucm93KGlsZFshaXMubmEoaWxkJGJlZXApLF0pLDEpYCUpLCB3aGljaCBvbmx5IGluY2x1ZGVkIG5lZ2F0aXZlIHZhbGVuY2UgYnV0IG5vdCB0YXNrIGRlbWFuZHMgb3IgdGFzayBjb250cm9sIGl0ZW1zLiANCmBgYHtyICB9DQojIHJlbW92aW5nIGFsbCByZXNwb25zZXMgdG8gdGhlIGZpcnN0IGRhaWx5IHN1cnZleSAobm90IGluY2x1ZGluZyB0YXNrIGRlbWFuZHMgYW5kIHRhc2sgY29udHJvbCkNCk4xIDwtIG5yb3coaWxkKSAjIHNhdmluZyBvcmlnaW5hbCBzYW1wbGUgc2l6ZSBmb3IgY29tcGFyaXNvbg0KaWxkIDwtIGlsZFtpbGQkYmVlcCE9MSxdICMgcmVtb3ZpbmcgcmVzcG9uc2VzIHRvIHRoZSBmaXJzdCBzdXJ2ZXkgb2YgZWFjaCBkYXkNCmNhdCgiUmVtb3ZlZCIsTjEtbnJvdyhpbGQpLCJyZXNwb25zZXMgKCIscm91bmQoMTAwKihOMS1ucm93KGlsZCkpL04xLDEpLCIlICkiKQ0KYGBgDQoNCkZpbmFsbHksIHdlIGluc3BlY3QgYW5kIHJlbW92ZSBhbGwgY2FzZXMgd2l0aCBtaXNzaW5nIHJlc3BvbnNlcyB0byBhbnkgaXRlbXMgKGxpc3Qtd2lzZSBkZWxldGlvbikuIFRoaXMgaXMgZG9uZSBieSBhcHBseWluZyB0aGUgYG5hLm9taXRgIGZ1bmN0aW9uIHRvIHRoZSBzdWJzZXQgb2YgdGhlIGBpbGRgIGRhdGFzZXQgdGhhdCBvbmx5IGluY2x1ZGVzIHRoZSBjb2x1bW5zIGNvbnNpZGVyZWQgZm9yIHRoZSBmb2xsb3dpbmcgc3RlcHMsIG5hbWVseSB0aGUgcGFydGljaXBhbnQgaWRlbnRpZmllciBgSURgLCB0aGUgdGVtcG9yYWwgY29vcmRpbmF0ZXMgb2YgdGhlIHJlc3BvbnNlcywgYW5kIHRoZSB0aHJlZSBtdWx0aS1pdGVtIHNjYWxlcy4gU3BlY2lmaWNhbGx5LCBpdGVtcyBhcmUgc2VsZWN0ZWQgd2l0aCB0aGUgYHBhc3RlMGAgZnVuY3Rpb24sIHdoaWNoIHBhc3RlcyB0aGUgbGV0dGVyIGlkZW50aWZ5aW5nIGVhY2ggc2NhbGUgKGkuZS4sIGB2YCBmb3IgbmVnYXRpdmUgdmFsZW5jZSwgYGRgIGZvciB0YXNrIGRlbWFuZHMsIGFuZCBgY2AgZm9yIHRhc2sgY29udHJvbCkgd2l0aCB0aGUgaXRlbSBudW1iZXIgKGUuZy4sIGBwYXN0ZTAoInYiLDE6MylgIHJldHVybnMgYSB2ZWN0b3Igd2l0aCB2YWx1ZXMgInYxIiwgInYyIiwgYW5kICJ2MyIpLg0KYGBge3IgIH0NCiMgbGlzdC13aXNlIGRlbGV0aW9uOiByZW1vdmluZyBjYXNlcyB3aXRoIG1pc3NpbmcgcmVzcG9uc2VzIHRvIGFueSBjb3JlIHZhcmlhYmxlDQpOMSA8LSBucm93KGlsZCkgIyBzYXZpbmcgb3JpZ2luYWwgc2FtcGxlIHNpemUgZm9yIGNvbXBhcmlzb24NCmlsZCA8LSANCiAgbmEub21pdChpbGRbLGMoIklEIiwgIyBwYXJ0aWNpcGFudCBpZGVudGlmaWVyDQogICAgICAgICAgICAgICAgICJSdW5UaW1lc3RhbXAiLCJTdWJtaXNzaW9uVGltZXN0YW1wIiwiZGF5IiwiYmVlcCIsICMgdGVtcG9yYWwgY29vcmRpbmF0ZXMNCiAgICAgICAgICAgICAgICAgcGFzdGUwKCJ2IiwxOjMpLHBhc3RlMCgiZCIsMTo0KSxwYXN0ZTAoImMiLDE6MykpXSkgIyBpdGVtIHNjb3Jlcw0KY2F0KCJSZW1vdmVkIixOMS1ucm93KGlsZCksInJlc3BvbnNlcyAoIixyb3VuZCgxMDAqKE4xLW5yb3coaWxkKSkvTjEsMSksIiUgKSIpDQpgYGANCg0KPGJyPg0KDQojIyMgMS4zLjIuIERvdWJsZSByZXNwb25zZXMNCg0KQXMgYSBzdWJzZXF1ZW50IHN0ZXAsIHdlIGluc3BlY3QgY2FzZXMgb2YgZG91YmxlIHJlc3BvbnNlcyAoaS5lLiwgdHdvIG9yIG1vcmUgcmVzcG9uc2VzIHdpdGggdGhlIHNhbWUgYElEYCwgYGRheWAsIGFuZCBgYmVlcGAgdmFsdWVzKS4gQWdhaW4sIHRoaXMgaXMgZG9uZSB3aXRoIHRoZSBgcGFzdGUwYCBmdW5jdGlvbiwgd2hpY2ggY3JlYXRlcyBhIHZhcmlhYmxlIGNvbWJpbmluZyBwYXJ0aWNpcGFudCwgZGF5LCBhbmQgYmVlcCBpZGVudGlmaWVycyBzbyB0aGF0IHdlIGNhbiBpZGVudGlmeSBhbmQgcmVtb3ZlIGFueSBjYXNlcyBvZiBkdXBsaWNhdGVkIHZhbHVlIGZvciB0aGlzIHZhcmlhYmxlLiBXZSBjYW4gc2VlIHRoYXQgbm8gZHVwbGljYXRlZCBjYXNlcyBhcmUgZGV0ZWN0ZWQgaW4gb3VyIGNhc2UuDQpgYGB7ciAgfQ0KIyBkZXRlY3RpbmcgZG91YmxlIHJlc3BvbnNlcyAoaS5lLiBzYW1lIElELCBkYXksIGFuZCBiZWVwIHZhbHVlKQ0KbnJvdyhpbGRbZHVwbGljYXRlZChwYXN0ZTAoaWxkJElELCBpbGQkZGF5LCBpbGQkYmVlcCkpLF0pICMgbm8gZG91YmxlIHJlc3BvbnNlcyBpbiB0aGUgZGF0YXNldA0KDQojICMgcnVuIHRoaXMgbGluZSB0byByZW1vdmUgZG91YmxlIHJlc3BvbnNlcw0KIyBpbGQgPC0gaWxkWyFkdXBsaWNhdGVkKHBhc3RlMChpbGQkSUQsIGlsZCRkYXksIGlsZCRiZWVwKSksXQ0KYGBgDQoNCjxicj4NCg0KIyMjIDEuMy4zLiBDYXJlbGVzcyByZXNwb25zZXMNCg0KSGVyZSwgd2UgaW5zcGVjdCBhbmQgZmlsdGVyIGNhc2VzIG9mIHBvdGVudGlhbGx5IGNhcmVsZXNzIHJlc3BvbnNlcyBhbmQgcmVzcG9uZGVudHMuIFNwZWNpZmljYWxseSwgZm9sbG93aW5nIFtDdXJyYW4gKDIwMTYpXSgjcmVmKSwgd2UgaWxsdXN0cmF0ZSBjYXJlbGVzcyByZXNwb25zZSBkZXRlY3Rpb24gYnkgbG9va2luZyBmb3IgY2FzZXMgd2l0aCBleGNlc3NpdmVseSBmYXN0IHJlc3BvbnNlIHRpbWUuIENvbnNpZGVyaW5nIHRoZSByZXBldGl0aXZlIG5hdHVyZSBvZiBFU00gZGVzaWducywgd2UgYXBwbHkgYSBtb3JlIGNvbnNlcnZhdGl2ZSBjcml0ZXJpb24gdGhhbiB0aGF0IHByb3Bvc2VkIGJ5IFtDdXJyYW4gKDIwMTYpXSgjcmVmKSAoaS5lLiwgbGVzcyB0aGFuIDIgc2Vjb25kcyBwZXIgaXRlbSkgYW5kIHdlIHJlbW92ZSBhbGwgcmVzcG9uc2UgdGFraW5nIDEuNSBzZWNvbmRzIHBlciBpdGVtLiBJbiBvdXIgY2FzZSwgZWFjaCBFU00gcXVlc3Rpb25uYWlyZSBpbmNsdWRlZCAyMSBpdGVtcyAoc2VlIFtNZW5naGluaSBldCBhbC4sIDIwMjNdKCNyZWYpKSwgcmVzdWx0aW5nIGluIGEgdG90YWwgY3V0LW9mZiB0aW1lIG9mIDIxICRcdGltZXMkIDEuNSBzZWNvbmRzID0gMzEuNSBzZWNvbmRzLiBXZSBjYW4gc2VlIHRoYXQgdGhlIHRpbWUgZGlmZmVyZW5jZSBiZXR3ZWVuIGBTdWJtaXNzaW9uVGltZXN0YW1wYCBhbmQgYFJ1blRpbWVzdGFtcGAgdmFsdWVzIGlzIGxvd2VyIHRoYW4gMzEuNSBzZWNvbmRzIG9ubHkgaW4gb25lIGNhc2UuDQpgYGB7ciAgfQ0KIyBkZXRlY3RpbmcgY2FzZXMgd2l0aCB0b3RhbCByZXNwb25zZSB0aW1lIGJlbG93IDMxLjUgc2Vjb25kcw0KbnJvdyhpbGRbZGlmZnRpbWUoaWxkJFN1Ym1pc3Npb25UaW1lc3RhbXAsaWxkJFJ1blRpbWVzdGFtcCx1bml0cz0ic2VjcyIpIDwgMzEuNSxdKQ0KDQojIHJlbW92aW5nIGNhc2VzIHdpdGggdG90YWwgcmVzcG9uc2UgdGltZSBiZWxvdyAzMS41IHNlY29uZHMNCmlsZCA8LSBpbGRbZGlmZnRpbWUoaWxkJFN1Ym1pc3Npb25UaW1lc3RhbXAsaWxkJFJ1blRpbWVzdGFtcCx1bml0cz0ic2VjcyIpID4gMzEuNSxdDQpgYGANCg0KPGJyPg0KDQojIyMgMS4zLjQuIENvbXBsaWFuY2UgcmF0ZSB7LnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30NCg0KRmluYWxseSwgd2UgaW5zcGVjdCB0aGUgcGFydGljaXBhbnRzJyBjb21wbGlhbmNlIHJhdGUgYW5kIGFwcGx5IG91ciBleGNsdXNpb24gY3JpdGVyaW9uIGJ5IHJlbW92aW5nIGFsbCBwYXJ0aWNpcGFudHMgd2l0aCBsZXNzIHRoYW4gMiB2YWxpZCBvYnNlcnZhdGlvbnMgcGVyIGRheS4gRmlyc3QsIHdlIHVzZSBhIGZvci1sb29wIHRvIGNvbXB1dGUgdGhlIHJlc3BvbnNlIHJhdGUgb2YgZWFjaCBwYXJ0aWNpcGFudCAoaS5lLiwgcGVyY2VudGFnZSBvZiBzdWJtaXR0ZWQgcmVzcG9uc2VzIG92ZXIgdGhlIDE4IHNjaGVkdWxlZCBxdWVzdGlvbm5haXJlcyBmb3IgZWFjaCBwYXJ0aWNpcGFudCkgYW5kLCB3aXRoaW4gdGhhdCBsb29wLCB3ZSBjb21wdXRlIHRoZSB0b3RhbCBudW1iZXIgb2Ygc3VibWl0dGVkIHJlc3BvbnNlcyBmb3IgZWFjaCBwYXJ0aWNpcGFudC1ieS1kYXkgY291cGxlLCBhZGRpbmcgdGhlc2UgdmFyaWFibGVzIHRvIHRoZSBgcHJlbHFzYCBkYXRhc2V0LiBTZWNvbmQsIHdlIHBsb3QgdGhlIGNyZWF0ZWQgcmVzcG9uc2UgcmF0ZSB2YXJpYWJsZXMuIEZpbmFsbHksIHdlIGV4Y2x1ZGUgcGFydGljaXBhbnRzIHdpdGggbGVzcyB0aGFuIDIgcmVzcG9uc2VzIHBlciBkYXkuDQpgYGB7ciAgZmlnLndpZHRoPTEyLGZpZy5oZWlnaHQ9M30NCiMgY29tcHV0aW5nIG92ZXJhbGwgYW5kIGRhaWx5IGNvbXBsaWFuY2UgcmF0ZQ0KZm9yKGkgaW4gMTpucm93KHByZWxxcykpeyAjIE5vLiByZXNwb25zZXMgb3ZlciB0b3RhbCBudW1iZXIgb2Ygc2NoZWR1bGVkIGRhdGEgcG9pbnRzIChuID0gMTgpDQogIHByZWxxc1tpLCJjb21wUmF0ZSJdIDwtIDEwMCpucm93KGlsZFtpbGQkSUQ9PWFzLmNoYXJhY3RlcihwcmVscXNbaSwiSUQiXSksXSkvMTgNCiAgZm9yKGRheSBpbiAxOjMpeyAjIGNvbXB1dGluZyBudW1iZXIgb2Ygbm9ubWlzc2luZyBkYXRhIHBvaW50cyBwZXIgZWFjaCBkYXkNCiAgICBwcmVscXNbaSxwYXN0ZTAoIm4uZGF5IixkYXkpXSA8LSBucm93KGlsZFtpbGQkSUQ9PWFzLmNoYXJhY3RlcihwcmVscXNbaSwiSUQiXSkgJiBpbGQkZGF5PT1kYXksXSkgfX0NCg0KIyBwbG90dGluZyBvcmlnaW5hbCBjb21wbGlhbmNlDQpwYXIobWZyb3c9YygxLDQpKQ0KZm9yKGkgaW4gYygiY29tcFJhdGUiLCJuLmRheTEiLCJuLmRheTIiLCJuLmRheTMiKSl7IGhpc3QocHJlbHFzWyxpXSxtYWluPWkpIH0NCg0KIyBleGNsdWRpbmcgcGFydGljaXBhbnRzIHdpdGggbGVzcyB0aGFuIDIgdmFsaWQgZGF0YSBwb2ludHMgcGVyIGRheQ0KTjIgPC0gbnJvdyhwcmVscXMpOyBOMSA8LSBucm93KGlsZCkgIyBzYXZpbmcgb3JpZ2luYWwgc2FtcGxlIHNpemVzIGZvciBjb21wYXJpc29uDQpwcmVscXMgPC0gcHJlbHFzW3ByZWxxcyRuLmRheTEgPj0gMiAmIHByZWxxcyRuLmRheTIgPj0gMiAmIHByZWxxcyRuLmRheTMgPj0gMixdICMgZXhjbHVkaW5nIHBhcnRpY2lwYW50cyBmcm9tIHByZWxxcw0KaWxkIDwtIGlsZFtpbGQkSUQgJWluJSBhcy5jaGFyYWN0ZXIocHJlbHFzJElEKSxdDQpjYXQoIlJlbW92ZWQiLE4yLW5yb3cocHJlbHFzKSwicGFydGljaXBhbnRzICgiLHJvdW5kKDEwMCooTjItbnJvdyhwcmVscXMpKS9OMiwxKSwNCiAgICAiJSApIGFuZCIsTjEtbnJvdyhpbGQpLCJvYnNlcnZhdGlvbnMgKCIscm91bmQoMTAwKihOMS1ucm93KGlsZCkpL04xLDEpLCIlICkiKQ0KDQojIHBsb3R0aW5nIHVwZGF0ZWQgY29tcGxpYW5jZQ0KcGFyKG1mcm93PWMoMSw0KSkNCmZvcihpIGluIGMoImNvbXBSYXRlIiwibi5kYXkxIiwibi5kYXkyIiwibi5kYXkzIikpeyBoaXN0KHByZWxxc1ssaV0sbWFpbj1pKSB9DQpgYGANCg0KPGJyPg0KDQojIyMgMS4zLjUuIEV4Y2x1ZGVkIGRhdGENCg0KSGVyZSwgd2UgY29tcHV0ZSB0aGUgdG90YWwgbnVtYmVyIG9mIGV4Y2x1ZGVkIG9ic2VydmF0aW9ucyBhbmQgcGFydGljaXBhbnRzIGJ5IGNvbXBhcmluZyB0aGUgb3JpZ2luYWwgc2FtcGxlIHNpemVzIHdpdGggdGhvc2Ugb2J0YWluZWQgYWZ0ZXIgYXBwbHlpbmcgYWxsIGRhdGEgY2xlYW5pbmcgcHJvY2VkdXJlcy4NCmBgYHtyICB9DQojIHJlc2V0dGluZyBJRCBsZXZlbHMNCmlsZCRJRCA8LSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKGlsZCRJRCkpDQpwcmVscXMkSUQgPC0gYXMuZmFjdG9yKGFzLmNoYXJhY3RlcihwcmVscXMkSUQpKQ0KDQojIHRvdGFsIG51bWJlciBhbmQgcGVyY2VudGFnZSBvZiBleGNsdWRlZCBwYXJ0aWNpcGFudHMNCm4yIC0gbmxldmVscyhpbGQkSUQpOyAxMDAqKG4yIC0gbGVuZ3RoKHRhYmxlKGlsZCRJRCkpKS9uMg0KDQojIHRvdGFsIG51bWJlciBhbmQgcGVyY2VudGFnZSBvZiBleGNsdWRlZCBvYnNlcnZhdGlvbnMNCm4xIC0gbnJvdyhpbGQpOyAxMDAqKG4xIC0gbnJvdyhpbGQpKS9uMQ0KYGBgDQoNCjxicj4NCg0KIyMgMS40LiBEYXRhIG1lcmdpbmcgey50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHN9DQoNCkhlcmUsIHdlIG1lcmdlIHRoZSB0aW1lLWludmFyaWFudCBkYXRhIGluY2x1ZGVkIGluIHRoZSB3aWRlLWZvcm0gYHByZWxxc2AgZGF0YXNldCAoaS5lLiwgcGFydGljaXBhbnRzJyBgYWdlYCBhbmQgYGdlbmRlcmApIHdpdGggdGhlIHRpbWUtdmFyeWluZyBkYXRhIGluY2x1ZGVkIGluIHRoZSBsb25nLWZvcm0gYGlsZGAgZGF0YXNldC4gVGhpcyBpcyBkb25lIHdpdGggdGhlIGBqb2luKClgIGZ1bmN0aW9uIGZyb20gdGhlIGBwbHlyYCBwYWNrYWdlIGJhc2VkIG9uIHRoZSBzaGFyZWQgdmFyaWFibGUgYElEYCwgaWRlbnRpZnlpbmcgYWxsIHRoZSBkYXRhIHBvaW50cyBhc3NvY2lhdGVkIHdpdGggdGhlIHNhbWUgcGFydGljaXBhbnQuDQpgYGB7ciAgfQ0KIyBkYXRhIG1lcmdpbmcNCmxpYnJhcnkocGx5cikgIyBvcGVuaW5nIHBseXIgcGFja2FnZSB0byB1c2UgdGhlIGpvaW4oKSBmdW5jdGlvbg0KaWxkIDwtIGpvaW4oaWxkLCAjIGxvbmctZm9ybSBkYXRhc2V0DQogICAgICAgICAgICBwcmVscXNbLGMoIklEIiwiYWdlIiwiZ2VuZGVyIildLCAjIHNlbGVjdGluZyBjb2x1bW5zIGZyb20gdGhlIHdpZGUtZm9ybSBkYXRhc2V0DQogICAgICAgICAgICBieSA9ICJJRCIpICMgc2V0dGluZyB0aGUgY29sdW1uIHNoYXJlZCBieSB0aGUgdHdvIGRhdGFzZXRzDQoNCiMgc2hvd2luZyBzb21lIGNvbHVtbnMgZnJvbSB0aGUgbWVyZ2VkIGRhdGFzZXQNCmlsZFssYygiSUQiLCJhZ2UiLCJnZW5kZXIiLCJkYXkiLCJiZWVwIiwidjEiKV0NCmBgYA0KDQo8YnI+DQoNCiMjIDEuNS4gRGF0YSBjZW50ZXJpbmcgey50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHN9DQoNCkhlcmUsIHdlIGNlbnRlciBhbnkgdGltZS12YXJ5aW5nIHZhcmlhYmxlIChpLmUuLCBFU00gaXRlbSBzY29yZXMgc3VjaCBhcyBgdjFgKSBieSBjb21wdXRpbmcgdGhlIGNvcnJlc3BvbmRpbmcgY2x1c3Rlci1tZWFuIChlLmcuLCBgdjFfbWVhbmApIGFuZCBjbHVzdGVyLW1lYW4tY2VudGVyZWQgdmFyaWFibGUgKGUuZy4sIGB2MV9jbWNgKSAoc2VlIHNlZSBbSGFtYWtlciAmIEdyYXNtYW4sIDIwMTVdKCNyZWYpOyBbV2FuZyAmIE1heHdlbGwsIDIwMTVdKCNyZWYpKS4gU2luY2UgaW4gUiB0aGUgc2FtZSByZXN1bHQgY2FuIGJlIGFjaGlldmVkIGluIG11bHRpcGxlIHdheXMsIHNvbWUgb2Ygd2hpY2ggbWlnaHQgYmUgbW9yZSBpbnR1aXRpdmUgZm9yIHNvbWUgdXNlcnMgYnV0IG5vdCBmb3Igb3RoZXJzLCB0aGlzIHN0ZXAgaXMgaW1wbGVtZW50ZWQgaW4gdHdvIGRpZmZlcmVudCB3YXlzLCBuYW1lbHkgdXNpbmcgYGJhc2VgIFIgYW5kIHdpdGggdGhlIGB0aWR5dmVyc2VgIHN5bnRheC4NCg0KIyMjIEJhc2UgUg0KDQpXaXRoIGBiYXNlYCBSLCBjbHVzdGVyIG1lYW5zIChuYW1lZCAidmFyaWFibGVfbWVhbiIpIGFyZSBjb21wdXRlZCB1c2luZyB0aGUgYGFnZ3JlZ2F0ZWAgZnVuY3Rpb24sIHdoaWNoIGFsbG93cyB0byBjb21wdXRlIHRoZSBtZWFuIG9mIG9uZSBvciBtb3JlIHZhcmlhYmxlcyAoaGVyZSwgdGhlIG5lZ2F0aXZlIHZhbGVuY2UsIHRhc2sgZGVtYW5kLCBhbmQgdGFzayBjb250cm9sIGl0ZW0gc2NvcmVzKSBiYXNlZCBvbiBhIGdyb3VwaW5nIHZhcmlhYmxlIChoZXJlLCB0aGUgcGFydGljaXBhbnQgaWRlbnRpZmllciB2YXJpYWJsZSBgSURgKS4gVGhlbiwgd2UgYWRkIGNsdXN0ZXIgbWVhbnMgdG8gdGhlIGBpbGRgIGxvbmctZm9ybSBkYXRhc2V0IGFuZCB3ZSB1c2UgYSBmb3ItbG9vcCBmb3IgY29tcHV0aW5nIGNsdXN0ZXItbWVhbi1jZW50ZXJlZCBzY29yZXMgKG5hbWVkICJ2YXJpYWJsZV9jbWMiKSBieSBzdWJ0cmFjdGluZyBjbHVzdGVyLW1lYW4gdmFsdWVzIGZyb20gdGhlIG9yaWdpbmFsIHZhcmlhYmxlIHZhbHVlcywgZm9yIGVhY2ggdGltZS12YXJ5aW5nIHZhcmlhYmxlLg0KYGBge3IgIH0NCiMgc2VsZWN0aW5nIHZhcmlhYmxlIG5hbWVzDQpWYXJOYW1lcyA8LSBjKCJ2MSIsInYyIiwidjMiLCJkMSIsImQyIiwiZDMiLCJkNCIsImMxIiwiYzIiLCJjMyIpDQoNCiMgY29tcHV0aW5nIGNsdXN0ZXItbWVhbiB2YWx1ZXMgb2YgdGltZS12YXJ5aW5nIHZhcmlhYmxlcw0KbWVhbnMgPC0gYWdncmVnYXRlKHggPSBpbGRbLFZhck5hbWVzXSwgIyB2YXJpYWJsZXMgdG8gYmUgYWdncmVnYXRlZA0KICAgICAgICAgICAgICAgICAgIGJ5ID0gbGlzdChpbGQkSUQpLCAjIGNsdXN0ZXIgdmFyaWFibGUgKGl0IHNob3VsZCBiZSBhIGxpc3QpDQogICAgICAgICAgICAgICAgICAgRlVOID0gbWVhbikgIyBhZ2dyZWdhdGluZyBmdW5jdGlvbiAobWVhbikNCmNvbG5hbWVzKG1lYW5zKSA8LSBjKCJJRCIsICMgcmVuYW1pbmcgdmFyaWFibGVzIHRvIGF2b2lkIGR1cGxpY2F0ZWQgbmFtZXMgYmVsb3cNCiAgICAgICAgICAgICAgICAgICAgIHBhc3RlMChWYXJOYW1lcywiX21lYW4iKSkNCg0KIyBqb2luaW5nIGNsdXN0ZXIgbWVhbnMgdG8gdGhlIGxvbmctZm9ybSBkYXRhc2V0DQppbGQgPC0gcGx5cjo6am9pbihpbGQsbWVhbnMsYnk9IklEIikNCg0KIyBjb21wdXRpbmcgY2x1c3Rlci1tZWFuLWNlbnRlcmVkIHZhbHVlcw0KZm9yKFZhck5hbWUgaW4gVmFyTmFtZXMpeyAjIGZvciBlYWNoIHRpbWUtdmFyeWluZyB2YXJpYWJsZQ0KICBpbGRbLHBhc3RlMChWYXJOYW1lLCJfY21jIildIDwtICMgdGhlIGNsdXN0ZXItbWVhbi1jZW50ZXJlZCB2YXJpYWJsZSAoX2NtYykuLi4NCiAgICBpbGRbLFZhck5hbWVdIC0gIyAuLi5pcyBlcXVhbCB0byB0aGUgb3JpZ2luYWwgdmFyaWFibGUuLi4NCiAgICBpbGRbLHBhc3RlMChWYXJOYW1lLCJfbWVhbiIpXSB9ICMgLi4ubWludXMgdGhlIGNsdXN0ZXItbWVhbiB2YXJpYWJsZSAoX21lYW4pLg0KDQojIHNob3dpbmcgZXhhbXBsZSB2YXJpYWJsZXMNCmlsZFssYygiSUQiLCJkYXkiLCJiZWVwIiwiYzEiLCJjMV9tZWFuIiwiYzFfY21jIiwiZDEiLCJkMV9tZWFuIiwiZDFfY21jIildDQpgYGANCg0KPGJyPg0KDQojIyMgVGlkeXZlcnNlDQoNCkhlcmUsIHdlIHJlcGxpY2F0ZSB0aGUgc2FtZSBvcGVyYXRpb25zIGluIHRocmVlIGFsdGVybmF0aXZlIHdheXMgYmFzZWQgb24gdGhlIGB0aWR5dmVyc2VgIHN5bnRheCAoc2VlIFtXaWNraGFtIGV0IGFsLiwgMjAyM10oI3JlZikpLiBJbiBvcHRpb24gQSwgd2UgdXNlIHRoZSBwaXBlIG9wZXJhdG9yIGAlPiVgIHRvIGNvbmNhdGVuYXRlIG9wZXJhdGlvbnMsIHRoZSBgZ3JvdXBfYnlgIGZ1bmN0aW9uIHRvIGdyb3VwIG9wZXJhdGlvbnMgYnkgcGFydGljaXBhbnQgYElEYCwgYW5kIHRoZSBgbXV0YXRlYCBmdW5jdGlvbiB0byBzcGVjaWZ5IHdoaWNoIG9wZXJhdGlvbnMgc2hvdWxkIGJlIGFwcGxpZWQgKGkuZS4sIGNvbXB1dGluZyBjbHVzdGVyLW1lYW4gYW5kIGNsdXN0ZXItbWVhbi1jZW50ZXJlZCB2YWx1ZXMpLiBJbiBvcHRpb24gQiwgd2UgZGlyZWN0bHkgdXNlIHRoZSBgbXV0YXRlYCBmdW5jdGlvbiB0byBzcGVjaWZ5IGJvdGggdGhlIG9wZXJhdGlvbnMgdG8gYmUgYXBwbGllZCBhbmQgdGhlIGdyb3VwaW5nIHZhcmlhYmxlIChzcGVjaWZpZWQgd2l0aCB0aGUgYXJndW1lbnQgYC5ieWApLiBGaW5hbGx5LCBvcHRpb24gQyBpcyBhbiBleHRlbnNpb24gb2Ygb3B0aW9uIEIgd2hlcmUgd2UgdXNlIHRoZSBgYWNyb3NzYCBmdW5jdGlvbiB0byByZXBlYXQgdGhlIG9wZXJhdGlvbnMgc3BlY2lmaWVkIGluIHRoZSBgLmZuc2AgYXJndW1lbnQgYWNyb3NzIGFsbCB0aGUgY29sdW1ucyBzcGVjaWZpZWQgaW4gdGhlIGAuY29sc2AgYXJndW1lbnQgb2YgdGhlIGBtdXRhdGVgIGZ1bmN0aW9uLiBJbiB0aGlzIHdheSwgaXQgaXMgcG9zc2libGUgdG8gYXZvaWQgbWFudWFsbHkgcmV3cml0aW5nIHRoZSBzYW1lIG9wZXJhdGlvbnMgZm9yIGVhY2ggdmFyaWFibGUsIGFzIGluIG9wdGlvbiBBIGFuZCBCLiANCmBgYHtyICBlY2hvPUZBTFNFLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCiMgdGhpcyBpcyBqdXN0IHRvIGF2b2lkIG91dHB1dHRpbmcgbG9uZyB0ZXh0IG1lc3NhZ2Ugd2hlbiBsb2FkaW5nIHRoZSBwYWNrYWdlDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmBgYA0KYGBge3IgIH0NCiMgbG9hZGluZyB0aWR5dmVyc2UgcGFja2FnZSBjb2xsZWN0aW9uDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCg0KIyBvcHRpb24gQTogbXV0YXRlIGFuZCBncm91cF9ieQ0KaWxkX3RpZHl2ZXJzZV9BIDwtIA0KICBpbGQgJT4lDQogIGdyb3VwX2J5KElEKSAlPiUgIyBncm91cGluZyBvcGVyYXRpb25zIGJ5IGNsdXN0ZXIgdmFyaWFibGUgIklEIg0KICBtdXRhdGUoYzFfbWVhbiA9IG1lYW4oYzEpLCAjIGNvbXB1dGluZyBjbHVzdGVyLW1lYW4gdmFyaWFibGVzIChvbmx5IGV4YW1wbGVzKQ0KICAgICAgICAgZDFfbWVhbiA9IG1lYW4oZDEpLA0KICAgICAgICAgYzFfY21jID0gYzEgLSBjMV9tZWFuLCAjIGNvbXB1dGluZyBjbHVzdGVyLW1lYW4tY2VudGVyZWQgdmFyaWFibGUgKG9ubHkgZXhhbXBsZXMpDQogICAgICAgICBkMV9jbWMgPSBkMSAtIGQxX21lYW4pIA0KaWxkX3RpZHl2ZXJzZV9BWyxjKCJJRCIsImRheSIsImJlZXAiLCJjMSIsImMxX21lYW4iLCJjMV9jbWMiLCJkMSIsImQxX21lYW4iLCJkMV9jbWMiKV0NCg0KIyBvcHRpb24gQjogbXV0YXRlIHdpdGggIi5ieSINCmlsZF90aWR5dmVyc2VfQiA8LSANCiAgbXV0YXRlKGlsZCwNCiAgICAgICAgIGMxX21lYW4gPSBtZWFuKGMxKSwgIyBjb21wdXRpbmcgY2x1c3Rlci1tZWFuIHZhcmlhYmxlcyAob25seSBleGFtcGxlcykNCiAgICAgICAgIGQxX21lYW4gPSBtZWFuKGQxKSwNCiAgICAgICAgIGMxX2NtYyA9IGMxIC0gYzFfbWVhbiwgIyBjb21wdXRpbmcgY2x1c3Rlci1tZWFuLWNlbnRlcmVkIHZhcmlhYmxlIChvbmx5IGV4YW1wbGVzKQ0KICAgICAgICAgZDFfY21jID0gZDEgLSBkMV9tZWFuLA0KICAgICAgICAgLmJ5ID0gSUQpICMgZ3JvdXBpbmcgb3BlcmF0aW9ucyBieSBjbHVzdGVyIHZhcmlhYmxlICJJRCINCmlsZF90aWR5dmVyc2VfQlssYygiSUQiLCJkYXkiLCJiZWVwIiwiYzEiLCJjMV9tZWFuIiwiYzFfY21jIiwiZDEiLCJkMV9tZWFuIiwiZDFfY21jIildDQoNCiMgb3B0aW9uIEM6IHJlcGVhdCBvcHRpb24gQiBvdmVyIG11bHRpcGxlIGNvbHVtbnMgdXNpbmcgdGhlICJhY3Jvc3MiIGNvbW1hbmQNCmlsZF90aWR5dmVyc2VfQyA8LQ0KICBtdXRhdGUoaWxkLA0KICAgICAgICAgYWNyb3NzKA0KICAgICAgICAgICAjIHNlbGVjdGluZyBhbGwgdGhlIGNvbHVtbnMgb24gd2hpY2ggcmVwZWF0aW5nIHRoZSBvcGVyYXRpb25zDQogICAgICAgICAgIC5jb2xzID0gYygidjEiLCJ2MiIsInYzIiwiZDEiLCJkMiIsImQzIiwiZDQiLCJjMSIsImMyIiwiYzMiKSwgDQogICAgICAgICAgIC5mbnMgPSBsaXN0KCAjIGxpc3Qgb2Ygb3BlcmF0aW9ucyB0byBiZSByZXBlYXRlZA0KICAgICAgICAgICAgIG1lYW4gPX4gbWVhbigueCksICMgY29tcHV0aW5nIGNsdXN0ZXItbWVhbiB2YXJpYWJsZQ0KICAgICAgICAgICAgIGNtYyA9fiAueCAtIG1lYW4oLngpICkpLCAjIGNvbXB1dGluZyBjbHVzdGVyLW1lYW4tY2VudGVyZWQgdmFyaWFibGUNCiAgICAgICAgIC5ieSA9IElEKSAjIGdyb3VwaW5nIG9wZXJhdGlvbnMgYnkgY2x1c3RlciB2YXJpYWJsZSAiSUQiDQppbGRfdGlkeXZlcnNlX0NbLGMoIklEIiwiZGF5IiwiYmVlcCIsImMxIiwiYzFfbWVhbiIsImMxX2NtYyIsImQxIiwiZDFfbWVhbiIsImQxX2NtYyIpXQ0KYGBgDQoNCjxicj4NCg0KIyMgMS42LiBQc3ljaG9tZXRyaWNzDQoNCkhlcmUsIHdlIGV2YWx1YXRlIHRoZSBwc3ljaG9tZXRyaWMgcHJvcGVydGllcyBvZiB0aGUgY29uc2lkZXJlZCBFU00gdmFyaWFibGVzLg0KDQojIyMgMS42LjEuIEl0ZW0gc2NvcmVzIHsudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQ0KDQpGaXJzdCwgd2UgdmlzdWFsaXplIHRoZSBkaXN0cmlidXRpb24gb2YsIGFuZCB0aGUgY29ycmVsYXRpb25zIGJldHdlZW4sIGl0ZW0gc2NvcmVzLiBXZSBjYW4gc2VlIHRoYXQgYWxsIGl0ZW0gc2NvcmVzIHNoYXJlIHRoZSBzYW1lIHJhbmdlICgxLTcpIGFuZCB0aGF0IG1vc3Qgc2NvcmVzIGFyZSBxdWl0ZSBzeW1tZXRyaWNhbGx5IGRpc3RyaWJ1dGVkLCBhbHRob3VnaCB3aXRoIHNvbWUgc2tld2VkIGRpc3RyaWJ1dGlvbnMgKGl0ZW1zIGBjMWAsIGBjMmAsIGFuZCBgYzNgKS4gQmV0dGVyIHN5bW1ldHJ5IGlzIHNob3duIGJ5IGNsdXN0ZXItbWVhbiBhbmQgY2x1c3Rlci1tZWFuLWNlbnRlcmVkIHZhbHVlcy4NCmBgYHtyICBmaWcud2lkdGg9MTIsZmlnLmhlaWdodD00fQ0KIyBzZWxlY3RpbmcgaXRlbXMgdG8gYmUgZXZhbHVhdGVkDQppdGVtcyA8LSBjKCJ2MSIsInYyIiwidjMiLCJkMSIsImQyIiwiZDMiLCJkNCIsImMxIiwiYzIiLCJjMyIpDQoNCiMgcGxvdHRpbmcgb3JpZ2luYWwgaXRlbSBzY29yZSBkaXN0cmlidXRpb25zDQpwYXIobWZyb3c9YygyLDUpKQ0KZm9yKGl0ZW0gaW4gaXRlbXMpeyBoaXN0KGlsZFssaXRlbV0sbWFpbj1pdGVtLHhsYWI9IiIsYnJlYWtzPTMwKSB9DQoNCiMgcGxvdHRpbmcgY2x1c3Rlci1tZWFuIHNjb3JlIGRpc3RyaWJ1dGlvbnMNCnBhcihtZnJvdz1jKDIsNSkpDQpmb3IoaXRlbSBpbiBpdGVtcyl7IGhpc3QoaWxkWyFkdXBsaWNhdGVkKGlsZCRJRCkscGFzdGUwKGl0ZW0sIl9tZWFuIildLG1haW49cGFzdGUwKGl0ZW0sIl9tZWFuIikseGxhYj0iIixicmVha3M9MzApIH0NCg0KIyBwbG90dGluZyBjbHVzdGVyLW1lYW4tY2VudGVyZWQgc2NvcmUgZGlzdHJpYnV0aW9ucw0KcGFyKG1mcm93PWMoMiw1KSkNCmZvcihpdGVtIGluIGl0ZW1zKXsgaGlzdChpbGRbLHBhc3RlMChpdGVtLCJfY21jIildLG1haW49cGFzdGUwKGl0ZW0sIl9jbWMiKSx4bGFiPSIiLGJyZWFrcz0zMCkgfQ0KYGBgDQoNCkhlcmUsIHdlIGNvbXB1dGUgYW5kIHZpc3VhbGl6ZSB0aGUgbGV2ZWwtc3BlY2lmaWMgemVyby1vcmRlciBjb3JyZWxhdGlvbnMgYW1vbmcgdGhlIGNvbnNpZGVyZWQgaXRlbXMuIExldmVsLTEgKHdpdGhpbi1pbmRpdmlkdWFsKSBhbmQgbGV2ZWwtMiAoYmV0d2Vlbi1pbmRpdmlkdWFsKSBjb3JyZWxhdGlvbnMgYXJlIGNvbXB1dGVkIGJ5IGNvcnJlbGF0aW5nIGNsdXN0ZXItbWVhbi1jZW50ZXJlZCAoKm4qID0gYHIgbnJvdyhpbGQpYCkgYW5kIGNsdXN0ZXItbWVhbiB2YWx1ZXMgKCpuKiA9IGByIG5yb3cocHJlbHFzKWApLCByZXNwZWN0aXZlbHkuIFdlIGNhbiBzZWUgdGhhdCBjb3JyZWxhdGlvbnMgYXJlIGluIHRoZSBleHBlY3RlZCBkaXJlY3Rpb25zLCB3aXRoIHN0cm9uZ2VyIGNvcnJlbGF0aW9ucyBhdCBsZXZlbCAyIChzaG93biBiZWxvdyB0aGUgbWFpbiBkaWFnb25hbCkgdGhhbiBhdCBsZXZlbCAxIChzaG93biBhYm92ZSB0aGUgbWFpbiBkaWFnb25hbCksIGFuZCBhbW9uZyBpdGVtIHNjb3JlcyBiZWxvbmdpbmcgdG8gdGhlIHNhbWUgc2NhbGUgdGhhbiBhbW9uZyBzY29yZXMgZnJvbSBkaWZmZXJlbnQgc2NhbGVzLg0KYGBge3Igd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9Nn0NCiMgY29tcHV0aW5nIGxldmVsLTEgY29ycmVsYXRpb25zDQpjb3IxIDwtIHJvdW5kKGNvcihpbGRbLGl0ZW1zXSksMikNCg0KIyBjb21wdXRpbmcgbGV2ZWwtMiBjb3JyZWxhdGlvbnMNCmNvcjIgPC0gcm91bmQoY29yKGlsZFshZHVwbGljYXRlZChpbGQkSUQpLHBhc3RlMChpdGVtcywiX21lYW4iKV0pLDIpDQoNCiMgdmlzdWFsaXppbmcgY29ycmVsYXRpb25zDQpsaWJyYXJ5KHBzeWNoKQ0KY29yMVtsb3dlci50cmkoY29yMSldIDwtIGNvcjJbbG93ZXIudHJpKGNvcjIpXSAjIG1lcmdpbmcgdGhlIHR3byBtYXRyaWNlcw0KY29yUGxvdChjb3IxKSAjIHBsb3R0aW5nIGNvcnJlbGF0aW9uIG1hdHJpeA0KYGBgDQoNCjxicj4NCg0KIyMjIDEuNi4yLiBSZWxpYWJpbGl0eSBpbmRpY2VzIHsudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQ0KDQpIZXJlLCB3ZSBjb21wdXRlIHJlbGlhYmlsaXR5IGluZGljZXMgYmFzZWQgb24gZ2VuZXJhbGl6YWJpbGl0eSB0aGVvcnksIHRoYXQgaXMgYnkgZml0dGluZyBhIHJhbmRvbS1pbnRlcmNlcHQtb25seSBtb2RlbCB0byBkZWNvbXBvc2UgdGhlIHZhcmlhbmNlIGluIGl0ZW0gc2NvcmVzIGJhc2VkIG9uIHBhcnRpY2lwYW50cywgaXRlbXMsIHRpbWUsIGFuZCB0aGVpciBpbnRlcmFjdGlvbnMgKHNlZSBbU2hyb3V0ICYgTGFuZSAoMjAxMildKCNyZWYpOyBbQ3JhbmZvcmQgZXQgYWwuLCAyMDA2XSgjcmVmKSkuIFRoaXMgaXMgZG9uZSB1c2luZyB0aGUgYG11bHRpbGV2ZWwucmVsaWFiaWxpdHkoKWAgZnVuY3Rpb24gZnJvbSB0aGUgYHBzeWNoYCBwYWNrYWdlLg0KYGBge3Igd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9Nn0NCiMgaXNvbGF0aW5nIGZvY3VzZWQgaXRlbXMNCml0ZW1zIDwtIGMoInYxIiwidjIiLCJ2MyIpDQoNCiMgY3JlYXRpbmcgdmFyaWFibGUgJ3RpbWUnIChqb2luaW5nIGRheSBhbmQgYmVlcCkNCmlsZCR0aW1lIDwtIHBhc3RlKGlsZCRkYXksIGlsZCRiZWVwKQ0KDQojIGNvbXB1dGluZyByZWxpYWJpbGl0eSBpbmRpY2VzIGZvciBuZWdhdGl2ZSB2YWxlbmNlIGl0ZW1zDQptdWx0aWxldmVsLnJlbGlhYmlsaXR5KHggPSBpbGQsICMgbG9uZy1mb3JtIGRhdGFzZXQNCiAgICAgICAgICAgICAgICAgICAgICAgZ3JwID0gIklEIiwgIyBjbHVzdGVyIHZhcmlhYmxlIChjYXRlZ29yaWNhbCkNCiAgICAgICAgICAgICAgICAgICAgICAgVGltZSA9ICJ0aW1lIiwgIyB0aW1lIHZhcmlhYmxlIChjYXRlZ29yaWNhbCkNCiAgICAgICAgICAgICAgICAgICAgICAgaXRlbXMgPSBpdGVtcywgIyBpdGVtIG5hbWVzDQogICAgICAgICAgICAgICAgICAgICAgIGxtZXIgPSBUUlVFLCBhb3YgPSBGQUxTRSAjIGFkZGl0aW9uYWwgYXJndW1lbnRzIHRvIGJlIGluY2x1ZGVkDQogICAgICAgICAgICAgICAgICAgICAgIClbYygiUmtGIiwgIlJjIildICMgc2VsZWN0aW5nIHRoZSB0YXJnZXQgY29lZmZpY2llbnRzDQoNCiMgcmVsaWFiaWxpdHkgaW5kaWNlcyBmb3IgdGFzayBkZW1hbmRzDQptdWx0aWxldmVsLnJlbGlhYmlsaXR5KGlsZCwgZ3JwPSJJRCIsIFRpbWU9InRpbWUiLCBpdGVtcz1jKCJkMSIsImQyIiwiZDMiLCJkNCIpLGxtZXI9VFJVRSwgYW92PUZBTFNFKVtjKCJSa0YiLCJSYyIpXQ0KDQojIHJlbGlhYmlsaXR5IGluZGljZXMgZm9yIHRhc2sgY29udHJvbA0KbXVsdGlsZXZlbC5yZWxpYWJpbGl0eShpbGQsIGdycD0iSUQiLCBUaW1lPSJ0aW1lIiwgaXRlbXM9YygiYzEiLCJjMiIsImMzIiksbG1lcj1UUlVFLCBhb3Y9RkFMU0UpW2MoIlJrRiIsIlJjIildDQpgYGANCg0KPGJyPg0KDQojIyMgMS42LjMuIE1DRkENCg0KSGVyZSwgd2UgcHJvdmlkZSBzb21lIGlsbHVzdHJhdGl2ZSBjb2RlIGV4ZW1wbGlmeWluZyBhIHdheSB0byBjb25kdWN0IGEgbXVsdGlsZXZlbCBjb25maXJtYXRvcnkgZmFjdG9yIGFuYWx5c2lzIChNQ0ZBKSBvZiB0aGUgY29uc2lkZXJlZCBpdGVtcywgYmFzZWQgb24gW0phY2sgJiBKb3JnZW5zZW4gKDIwMTcpXSgjcmVmKS4gU3BlY2lmaWNhbGx5LCB3ZSBmaXQgYW5kIGNvbXBhcmUgYSBjb25maWd1cmFsIG1vZGVsIGBmaXQuY29uZmAgKHdpdGggdGhlIHNhbWUgZmFjdG9yIHN0cnVjdHVyZSBhY3Jvc3MgbGV2ZWxzKSBhbmQgYSB3ZWFrLWludmFyaWFuY2UgbW9kZWwgYGZpdC53aW52YCAod2l0aCBib3RoIHRoZSBzYW1lIHN0cnVjdHVyZSBhbmQgZXF1aXZhbGVudCBmYWN0b3IgbG9hZGluZ3MgYWNyb3NzIGxldmVscykuIFdlIGNhbiBzZWUgdGhhdCB0aGUgdHdvIG1vZGVscyBmaXQgdGhlIGRhdGEgY29tcGFyYWJseSwgYW5kIHdlIHRydXN0IHRoZSB3ZWFrLWludmFyaWFuY2UgbW9kZWwgYGZpdC53aW52YC4NCmBgYHtyIG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCiMgbW9kZWwgc3BlY2lmaWNhdGlvbjogY29uZmlndXJhbCBtb2RlbCAoc2FtZSBzdHJ1Y3R1cmUgYWNyb3NzIGxldmVscykNCm0uY29uZiA8LSAnbGV2ZWw6IDENCiAgICAgICAgICAgTmVnVmFsX3cgPX4gdjEgKyB2MiArIHYzDQogICAgICAgICAgIHRhc2tEZW1fdyA9fiBkMSArIGQyICsgZDMgKyBkNA0KICAgICAgICAgICB0YXNrQ29uX3cgPX4gYzEgKyBjMiArIGMzDQogICAgICAgICAgIA0KICAgICAgICAgICBsZXZlbDogMg0KICAgICAgICAgICBOZWdWYWxfYiA9fiB2MSArIHYyICsgdjMNCiAgICAgICAgICAgdGFza0RlbV9iID1+IGQxICsgZDIgKyBkMyArIGQ0DQogICAgICAgICAgIHRhc2tDb25fYiA9fiBjMSArIGMyICsgYzMnDQoNCiMgbW9kZWwgc3BlY2lmaWNhdGlvbjogd2Vhay1pbnZhcmlhbmNlIG1vZGVsIChzYW1lIHN0cnVjdHVyZSBhbmQgbG9hZGluZ3MgYWNyb3NzIGxldmVscykNCm0ud2ludiA8LSAnbGV2ZWw6IDENCiAgICAgICAgICAgTmVnVmFsX3cgPX4gYSp2MSArIGIqdjIgKyBjKnYzDQogICAgICAgICAgIHRhc2tEZW1fdyA9fiBkKmQxICsgZSpkMiArIGYqZDMgKyBnKmQ0DQogICAgICAgICAgIHRhc2tDb25fdyA9fiBoKmMxICsgaSpjMiArIGoqYzMNCiAgICAgICAgICAgDQogICAgICAgICAgIGxldmVsOiAyDQogICAgICAgICAgIE5lZ1ZhbF9iID1+IGEqdjEgKyBiKnYyICsgYyp2Mw0KICAgICAgICAgICB0YXNrRGVtX2IgPX4gZCpkMSArIGUqZDIgKyBmKmQzICsgZypkNA0KICAgICAgICAgICB0YXNrQ29uX2IgPX4gaCpjMSArIGkqYzIgKyBqKmMzDQogICAgICAgICAgICcNCg0KIyBtb2RlbCBmaXQgKG5vdGU6IHNvbWUgcGFydGljaXBhbnRzIHNob3cgbm8gdmFyaWFuY2UgaW4gc29tZSBpdGVtcywgd2hpY2ggaXMgcXVpdGUgY29tbW9uKQ0KbGlicmFyeShsYXZhYW4pDQpmaXQuY29uZiA8LSBjZmEobW9kZWwgPSBtLmNvbmYsIGRhdGEgPSBpbGQsIGNsdXN0ZXI9IklEIiwgc3RkLmx2PVRSVUUpDQpmaXQud2ludiA8LSBjZmEobW9kZWwgPSBtLndpbnYsIGRhdGEgPSBpbGQsIGNsdXN0ZXI9IklEIiwgc3RkLmx2PVRSVUUpDQoNCiMgZml0IGluZGljZXMNCnJvdW5kKGxhdkluc3BlY3QoZml0LmNvbmYsIHdoYXQgPSAiZml0IilbYygicm1zZWEiLCJjZmkiLCJzcm1yX3dpdGhpbiIsInNybXJfYmV0d2VlbiIpXSwzKSAjIGNvbmZpZ3VyYWwNCnJvdW5kKGxhdkluc3BlY3QoZml0LndpbnYsIHdoYXQgPSAiZml0IilbYygicm1zZWEiLCJjZmkiLCJzcm1yX3dpdGhpbiIsInNybXJfYmV0d2VlbiIpXSwzKSAjIHdlYWsgaW52YXJpYW5jZQ0KYGBgDQoNClRoZSBpbnNwZWN0aW9uIG9mIHRoZSBzdGFuZGFyZGl6ZWQgcGFyYW1ldGVycyBlc3RpbWF0ZWQgYnkgdGhlIHdlYWstaW52YXJpYW5jZSBtb2RlbCByZXZlYWxzIHNpZ25pZmljYW50IGZhY3RvciBsb2FkaW5ncyByYW5naW5nIGZyb20gYHIgcm91bmQobWluKHN0YW5kYXJkaXplZHNvbHV0aW9uKGZpdC53aW52KVtzdGFuZGFyZGl6ZWRzb2x1dGlvbihmaXQud2ludikkb3A9PSI9fiIsImVzdC5zdGQiXSksMilgIHRvIGByIHJvdW5kKG1heChzdGFuZGFyZGl6ZWRzb2x1dGlvbihmaXQud2ludilbc3RhbmRhcmRpemVkc29sdXRpb24oZml0LndpbnYpJG9wPT0iPX4iLCJlc3Quc3RkIl0pLDIpYC4gVGhlIG1vZGVsIGFsc28gZXN0aW1hdGVzIHNpZ25pZmljYW50IGNvcnJlbGF0aW9ucyBhbW9uZyBsYXRlbnQgdmFyaWFibGVzIGluIHRoZSBleHBlY3RlZCBkaXJlY3Rpb25zLCB3aXRoIHRoZSBvbmx5IGV4Y2VwdGlvbiBvZiB0aGF0IGJldHdlZW4gZGVtYW5kcyBhbmQgY29udHJvbCBhdCBsZXZlbCAyIChub3Qgc2lnbmlmaWNhbnQpLiBPdmVyYWxsLCB0aGVzZSByZXN1bHRzIHN1cHBvcnQgdGhlIHZhbGlkaXR5IG9mIHRoZSBtZWFzdXJlbWVudCBtb2RlbCBoeXBvdGhlc2l6ZWQgZm9yIHRoZSBjb25zaWRlcmVkIGl0ZW1zLg0KYGBge3IgfQ0KIyBmYWN0b3IgbG9hZGluZ3MgZnJvbSB0aGUgc2VsZWN0ZWQgbW9kZWwgKHdlYWsgaW52YXJpYW5jZSkNCnAgPC0gc3RhbmRhcmRpemVkc29sdXRpb24oZml0LndpbnYpICMgc3RhbmRhcmRpemVkIGNvZWZmaWNpZW50cw0KcFtwJG9wPT0iPX4iLF0gIyBzZWxlY3RpbmcgZmFjdG9yIGxvYWRpbmdzDQoNCiMgY29ycmVsYXRpb25zIGFtb25nIGxhdGVudCBmYWN0b3JzDQpwW3AkbGhzJWluJWMoIk5lZ1ZhbF93IiwidGFza0RlbV93IiwidGFza0Nvbl93IikgJiBwJGxocyAhPSBwJHJocyAmIHAkb3A9PSJ+fiIsXSAjIGxldmVsIDENCnBbcCRsaHMlaW4lYygiTmVnVmFsX2IiLCJ0YXNrRGVtX2IiLCJ0YXNrQ29uX2IiKSAmIHAkbGhzICE9IHAkcmhzICYgcCRvcD09In5+IixdICMgbGV2ZWwgMg0KYGBgDQoNCjxicj4NCg0KIyMjIDEuNi40LiBMZXZlbC1zcGVjaWZpYyByZWxpYWJpbGl0eSB7LnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30NCg0KRmluYWxseSwgd2UgdXNlIHRoZSBNQ0ZBIG1vZGVsIHNlbGVjdGVkIGFib3ZlIHRvIGNvbXB1dGUgbGV2ZWwtc3BlY2lmaWMgTWNEb25hbGQncyAkXG9tZWdhJCBjb2VmZmljaWVudHMgZm9yIGVhY2ggc2NhbGUgKHNlZSBbR2VsZGhvZiBldCBhbC4gMjAxNF0oI3JlZikpLiBXZSBjYW4gc2VlIHRoYXQgYWxsICRcb21lZ2EkIGNvZWZmaWNpZW50cyBhcmUgc2F0aXNmYWN0b3J5IHdpdGggdmFsdWVzIGhpZ2hlciB0aGFuIDAuNzAgYW5kIGhpZ2hlciBjb2VmZmljaWVudHMgYXQgbGV2ZWwgMiB0aGFuIGF0IGxldmVsIDEuDQpgYGB7ciB9DQojIG9tZWdhIHdpdGhpbiBuZWdhdGl2ZSB2YWxlbmNlDQpzbCA8LSBwW3Akb3A9PSI9fiIgJiBzdWJzdHIocCRyaHMsMSwxKT09InYiLCJlc3Quc3RkIl1bMTozXSAjIHNlbGVjdGluZyBmYWN0b3IgbG9hZGluZ3MgYXQgbGV2ZWwgMQ0Kcm91bmQoIHN1bShzbCleMiAvICMgb21lZ2EgPSBzdW0gb2Ygc3F1YXJlZCBsb2FkaW5ncyAvDQogICAgICAgICAoc3VtKHNsKV4yICsgc3VtKDEgLSBzbF4yKSkgLDIpICMgKHN1bSBvZiBzcXVhcmVkIGxvYWRpbmdzICsgcmVzaWR1YWwgdmFyaWFuY2VzKQ0KDQojIG9tZWdhIHdpdGhpbiAtIHRhc2sgZGVtYW5kcw0Kc2wgPC0gcFtwJG9wPT0iPX4iICYgc3Vic3RyKHAkcmhzLDEsMSk9PSJkIiwiZXN0LnN0ZCJdWzE6NF0NCnJvdW5kKCBzdW0oc2wpXjIgLyAoc3VtKHNsKV4yICsgc3VtKDEgLSBzbF4yKSkgLDIpIA0KDQojIG9tZWdhIHdpdGhpbiAtIHRhc2sgY29udHJvbA0Kc2wgPC0gcFtwJG9wPT0iPX4iICYgc3Vic3RyKHAkcmhzLDEsMSk9PSJjIiwiZXN0LnN0ZCJdWzE6M10gDQpyb3VuZCggc3VtKHNsKV4yIC8gKHN1bShzbCleMiArIHN1bSgxIC0gc2xeMikpICwyKSANCg0KIyBvbWVnYSBiZXR3ZWVuIC0gbmVnYXRpdmUgdmFsZW5jZQ0Kc2wgPC0gcFtwJG9wPT0iPX4iICYgc3Vic3RyKHAkcmhzLDEsMSk9PSJ2IiwiZXN0LnN0ZCJdWzQ6Nl0NCnJvdW5kKCBzdW0oc2wpXjIgLyAoc3VtKHNsKV4yICsgc3VtKDEgLSBzbF4yKSkgLDIpIA0KDQojIG9tZWdhIGJldHdlZW4gLSB0YXNrIGRlbWFuZHMNCnNsIDwtIHBbcCRvcD09Ij1+IiAmIHN1YnN0cihwJHJocywxLDEpPT0iZCIsImVzdC5zdGQiXVs1OjZdIA0Kcm91bmQoIHN1bShzbCleMiAvIChzdW0oc2wpXjIgKyBzdW0oMSAtIHNsXjIpKSAsMikgDQoNCiMgb21lZ2EgYmV0d2VlbiAtIHRhc2sgY29udHJvbA0Kc2wgPC0gcFtwJG9wPT0iPX4iICYgc3Vic3RyKHAkcmhzLDEsMSk9PSJjIiwiZXN0LnN0ZCJdWzQ6Nl0NCnJvdW5kKCBzdW0oc2wpXjIgLyAoc3VtKHNsKV4yICsgc3VtKDEgLSBzbF4yKSkgLDIpIA0KYGBgDQoNCk9mIG5vdGUsIHRoZSBzYW1lIGNvZWZmaWNpZW50cyBjYW4gYmUgb2J0YWluZWQgbW9yZSBlZmZlY3RpdmVseSAoaS5lLiwgd2l0aG91dCBmaXR0aW5nIE1DRkEgbW9kZWxzKSBieSB1c2luZyB0aGUgYG9tZWdhU0VNYCBmdW5jdGlvbiBvZiB0aGUgYG11bHRpbGV2ZWxUb29sc2AgcGFja2FnZS4NCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQojIGxvYWRpbmcgbXVsdGlsZXZlbFRvb2xzIGxpYnJhcnkNCmxpYnJhcnkobXVsdGlsZXZlbFRvb2xzKQ0KDQojIE5lZ2F0aXZlIHZhbGVuY2UNCm9tZWdhU0VNKGl0ZW1zPXBhc3RlMCgidiIsMTozKSwgaWQgPSJJRCIsIGRhdGE9aWxkKSRSZXN1bHRzDQoNCiMgVGFzayBkZW1hbmQNCm9tZWdhU0VNKGl0ZW1zPXBhc3RlMCgiZCIsMTo0KSwgaWQgPSJJRCIsIGRhdGE9aWxkKSRSZXN1bHRzDQoNCiMgVGFzayBjb250cm9sDQpvbWVnYVNFTShpdGVtcz1wYXN0ZTAoImMiLDE6MyksIGlkID0iSUQiLCBkYXRhPWlsZCkkUmVzdWx0cw0KYGBgDQoNCjxicj4NCg0KIyMgMS43LiBDb21wb3NpdGUgc2NvcmVzIHsudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQ0KDQpIZXJlLCB3ZSBjb21wdXRlIHRoZSBjb21wb3NpdGUgc2NvcmVzIGZvciBlYWNoIHNjYWxlIGJ5IGF2ZXJhZ2luZyB0aGUgY29ycmVzcG9uZGluZyBpdGVtIHNjb3Jlcy4gVGhlbiB3ZSBjb21wdXRlIHRoZSBjbHVzdGVyLW1lYW4gYW5kIHRoZSBjbHVzdGVyLW1lYW4tY2VudGVyZWQgdmVyc2lvbnMgb2YgdGhlIGNvbXBvc2l0ZSBzY29yZXMgdXNpbmcgdGhlIHNhbWUgcHJvY2VkdXJlcyBzaG93biBpbiBTdGVwIDUuICBBcyBkb25lIGFib3ZlLCB3ZSBzaG93IGhvdyB0byBpbXBsZW1lbnQgdGhpcyBzdGVwIGJ5IHVzaW5nIGJvdGggYGJhc2VgIFIgYW5kLCBhbHRlcm5hdGl2ZWx5LCB0aGUgYHRpZHl2ZXJzZWAgc3ludGF4Lg0KDQojIyMgQmFzZSBSDQoNCldpdGggYGJhc2VgIFIsIHdlIHVzZSB0aGUgYGFwcGx5YCBmdW5jdGlvbiB0byBjb21wdXRlIHRoZSBjb21wb3NpdGUgc2NvcmVzIGBOVmAsIGBURGAsIGFuZCBgVENgIGJ5IGNvbXB1dGluZyB0aGUgbWVhbiBzY29yZSBieSByb3cuIFRoZW4sIHdlIHVzZSB0aGUgc2FtZSBjb2RlIHNob3duIGluIHNlY3Rpb24gMS41IHRvIGNvbXB1dGUgdGhlIGNsdXN0ZXItbWVhbiAobmFtZWQgYE5WYmAsIGBURGJgLCBhbmQgYFRDYmApIGFuZCBjbHVzdGVyLW1lYW4tY2VudGVyZWQgc2NvcmVzIChuYW1lZCBgTlZ3YCwgYFREd2AsIGFuZCBgVEN3YCkuDQpgYGB7ciAgfQ0KIyBjb21wdXRpbmcgY29tcG9zaXRlIHNjb3Jlcw0KaWxkJE5WIDwtIGFwcGx5KGlsZFssYygidjEiLCJ2MiIsInYzIildLDEsbWVhbixuYS5ybT1UUlVFKSAjIE5lZ2F0aXZlIFZhbGVuY2UNCmlsZCRURCA8LSBhcHBseShpbGRbLGMoImQxIiwiZDIiLCJkMyIsImQ0IildLDEsbWVhbixuYS5ybT1UUlVFKSAjIFRhc2sgRGVtYW5kcw0KaWxkJFRDIDwtIGFwcGx5KGlsZFssYygiYzEiLCJjMiIsImMzIildLDEsbWVhbixuYS5ybT1UUlVFKSAjIFRhc2sgQ29udHJvbA0KDQojIHNlbGVjdGluZyB2YXJpYWJsZSBuYW1lcw0KVmFyTmFtZXMgPC0gYygiTlYiLCJURCIsIlRDIikNCg0KIyBjb21wdXRpbmcgY2x1c3Rlci1tZWFuIHZhbHVlcyBvZiB0aW1lLXZhcnlpbmcgdmFyaWFibGVzIChzZWUgc2VjdGlvbiAxLjUpDQptZWFucyA8LSBhZ2dyZWdhdGUoeD1pbGRbLFZhck5hbWVzXSxieT1saXN0KGlsZCRJRCksRlVOPW1lYW4pIA0KY29sbmFtZXMobWVhbnMpIDwtIGMoIklEIixwYXN0ZTAoVmFyTmFtZXMsImIiKSkNCmlsZCA8LSBwbHlyOjpqb2luKGlsZCxtZWFucyxieT0iSUQiKQ0KDQojIGNvbXB1dGluZyBjbHVzdGVyLW1lYW4tY2VudGVyZWQgdmFsdWVzIChzZWUgc2VjdGlvbiAxLjUpDQpmb3IoVmFyTmFtZSBpbiBWYXJOYW1lcyl7IA0KICBpbGRbLHBhc3RlMChWYXJOYW1lLCJ3IildIDwtIGlsZFssVmFyTmFtZV0gLSBpbGRbLHBhc3RlMChWYXJOYW1lLCJiIildIH0gDQoNCiMgc2hvd2luZyBleGFtcGxlIHZhcmlhYmxlcw0KaWxkWyxjKCJJRCIsImRheSIsImJlZXAiLCJOViIsIk5WYiIsIk5WdyIpXQ0KYGBgDQoNCkhlcmUsIHdlIHZpc3VhbGl6ZSB0aGUgZGlzdHJpYnV0aW9ucyBvZiB0aGUgcmVzdWx0aW5nIGNvbXBvc2l0ZSBzY29yZXMuIFdlIGNhbiBzZWUgdGhhdCBjb21wb3NpdGUgc2NvcmVzIGFyZSBxdWl0ZSBzeW1tZXRyaWNhbGx5IGRpc3RyaWJ1dGVkLCBhbHRob3VnaCB3aXRoIHNvbWUgcG9zaXRpdmUgc2tld25lc3MgZm9yIG5lZ2F0aXZlIHZhbGVuY2UuIENsdXN0ZXItbWVhbi1jZW50ZXJlZCBzY29yZSBkaXN0cmlidXRpb25zIGFyZSBtb3JlIHN5bW1ldHJpYyB0aGFuIGNsdXN0ZXItbWVhbiBkaXN0cmlidXRpb25zLg0KYGBge3IgZmlnLndpZHRoPTgsZmlnLmhlaWdodD0yfQ0KIyB2aXN1YWxpemluZyBjb21wb3NpdGUgc2NvcmUgZGlzdHJpYnV0aW9ucw0KcGFyKG1mcm93PWMoMSwzKSkNCmZvcihWYXJOYW1lIGluIFZhck5hbWVzKXsgDQogIGhpc3QoaWxkWyxWYXJOYW1lXSxtYWluPVZhck5hbWUseGxhYj0iIixicmVha3M9MzApIH0NCg0KIyB2aXN1YWxpemluZyBjbHVzdGVyIG1lYW5zIG9mIGNvbXBvc2l0ZSBzY29yZXMNCmZvcihWYXJOYW1lIGluIHBhc3RlMChWYXJOYW1lcywiYiIpKXsNCiAgaGlzdChpbGRbIWR1cGxpY2F0ZWQoaWxkJElEKSxWYXJOYW1lXSxtYWluPVZhck5hbWUseGxhYj0iIixicmVha3M9MzApIH0NCg0KIyB2aXN1YWxpemluZyBjbHVzdGVyLW1lYW4tY2VudGVyZWQgY29tcG9zaXRlIHNjb3Jlcw0KZm9yKFZhck5hbWUgaW4gcGFzdGUwKFZhck5hbWVzLCJ3IikpeyANCiAgaGlzdChpbGRbLFZhck5hbWVdLG1haW49VmFyTmFtZSx4bGFiPSIiLGJyZWFrcz0zMCkgfQ0KYGBgDQoNCjxicj4NCg0KIyMjIFRpZHl2ZXJzZQ0KDQpIZXJlLCB3ZSByZXBsaWNhdGUgdGhlIHNhbWUgb3BlcmF0aW9ucyBpbiB0d28gYWx0ZXJuYXRpdmUgd2F5cyBiYXNlZCBvbiB0aGUgYHRpZHl2ZXJzZWAgc3ludGF4IChzZWUgW1dpY2toYW0gZXQgYWwuLCAyMDIzXSgjcmVmKSkuIEluIG9wdGlvbiBBLCB3ZSB1c2UgdGhlIHBpcGUgb3BlcmF0b3IgYCU+JWAgdG8gY29uY2F0ZW5hdGUgb3BlcmF0aW9ucywgdGhlIGBncm91cF9ieWAgZnVuY3Rpb24gdG8gZ3JvdXAgb3BlcmF0aW9ucyBieSBwYXJ0aWNpcGFudCBgSURgLCBhbmQgdGhlIGBtdXRhdGVgIGZ1bmN0aW9uIHRvIHNwZWNpZnkgd2hpY2ggb3BlcmF0aW9ucyBzaG91bGQgYmUgYXBwbGllZCAoaS5lLiwgY29tcHV0aW5nIGNvbXBvc2l0ZSBzY29yZXMgYW5kIHRoZWlyIGNsdXN0ZXIgbWVhbnMgYW5kIGNsdXN0ZXItbWVhbi1jZW50ZXJlZCB2YWx1ZXMpLiBJbiBvcHRpb24gQiwgd2UgZGlyZWN0bHkgdXNlIHRoZSBgbXV0YXRlYCBmdW5jdGlvbiB0byBzcGVjaWZ5IGFsbCBvcGVyYXRpb25zIHRvIGJlIGFwcGxpZWQgYW5kIHRoZSBncm91cGluZyB2YXJpYWJsZSAoc3BlY2lmaWVkIHdpdGggdGhlIGFyZ3VtZW50IGAuYnlgKS4NCmBgYHtyICB9DQojIGxvYWRpbmcgdGlkeXZlcnNlIHBhY2thZ2UgY29sbGVjdGlvbg0KbGlicmFyeSh0aWR5dmVyc2UpDQoNCiMgb3B0aW9uIEE6IG11dGF0ZSBhbmQgZ3JvdXBfYnkNCmlsZF90aWR5dmVyc2VfQSA8LSANCiAgaWxkICU+JQ0KICBncm91cF9ieShJRCkgJT4lICMgZ3JvdXBpbmcgb3BlcmF0aW9ucyBieSBjbHVzdGVyIHZhcmlhYmxlICJJRCINCiAgICAgICAgICMgY29tcHV0aW5nIGNvbXBvc2l0ZSBzY29yZXMNCiAgbXV0YXRlKE5WID0gbWVhbihjKHYxLHYyLHYzKSksIA0KICAgICAgICAgVEQgPSBtZWFuKGMoZDEsZDIsZDMsZDQpKSwNCiAgICAgICAgIFRDID0gbWVhbihjKGMxLGMyLGMzKSksDQogICAgICAgICAjIGNvbXB1dGluZyBjbHVzdGVyLW1lYW4gdmFyaWFibGVzDQogICAgICAgICBOVl9tZWFuID0gbWVhbihOViksDQogICAgICAgICBURF9tZWFuID0gbWVhbihURCksDQogICAgICAgICBUQ19tZWFuID0gbWVhbihUQyksDQogICAgICAgICAjIGNvbXB1dGluZyBjbHVzdGVyLW1lYW4tY2VudGVyZWQgdmFyaWFibGVzDQogICAgICAgICBOVl9jbWMgPSBOViAtIE5WX21lYW4sDQogICAgICAgICBURF9jbWMgPSBURCAtIFREX21lYW4sDQogICAgICAgICBUQ19jbWMgPSBUQyAtIFRDX21lYW4pIA0KaWxkX3RpZHl2ZXJzZV9BWyxjKCJJRCIsImRheSIsImJlZXAiLCJjMSIsImMxX21lYW4iLCJjMV9jbWMiLCJkMSIsImQxX21lYW4iLCJkMV9jbWMiKV0NCg0KIyBvcHRpb24gQjogbXV0YXRlIHdpdGggIi5ieSINCmlsZF90aWR5dmVyc2VfQiA8LSANCiAgbXV0YXRlKGlsZCwNCiAgICAgICAgICMgY29tcHV0aW5nIGNvbXBvc2l0ZSBzY29yZXMNCiAgICAgICAgIE5WID0gbWVhbihjKHYxLHYyLHYzKSksIA0KICAgICAgICAgVEQgPSBtZWFuKGMoZDEsZDIsZDMsZDQpKSwNCiAgICAgICAgIFRDID0gbWVhbihjKGMxLGMyLGMzKSksDQogICAgICAgICAjIGNvbXB1dGluZyBjbHVzdGVyLW1lYW4gdmFyaWFibGVzDQogICAgICAgICBOVl9tZWFuID0gbWVhbihOViksDQogICAgICAgICBURF9tZWFuID0gbWVhbihURCksDQogICAgICAgICBUQ19tZWFuID0gbWVhbihUQyksDQogICAgICAgICAjIGNvbXB1dGluZyBjbHVzdGVyLW1lYW4tY2VudGVyZWQgdmFyaWFibGVzDQogICAgICAgICBOVl9jbWMgPSBOViAtIE5WX21lYW4sDQogICAgICAgICBURF9jbWMgPSBURCAtIFREX21lYW4sDQogICAgICAgICBUQ19jbWMgPSBUQyAtIFRDX21lYW4sDQogICAgICAgICAuYnkgPSBJRCkgIyBncm91cGluZyBvcGVyYXRpb25zIGJ5IGNsdXN0ZXIgdmFyaWFibGUgIklEIg0KaWxkX3RpZHl2ZXJzZV9CWyxjKCJJRCIsImRheSIsImJlZXAiLCJjMSIsImMxX21lYW4iLCJjMV9jbWMiLCJkMSIsImQxX21lYW4iLCJkMV9jbWMiKV0NCmBgYA0KDQo8YnI+DQoNCiMjIDEuOC4gTGFnZ2luZyBhbmQgbGVhZGluZyB7LnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30NCg0KSGVyZSwgd2UgcHJvdmlkZSBzb21lIGNvZGUgZXhlbXBsaWZ5aW5nIGhvdyB0byBtYW5pcHVsYXRlIElMRCBkYXRhIHRvIG1vdmUgYSB2YXJpYWJsZSAodGFzayBkZW1hbmRzKSBvbmUgdGltZSBwb2ludCBiYWNrd2FyZCAobGFnZ2luZykgb3IgZm9yd2FyZCAobGVhZGluZykgLCBhbHRob3VnaCBzdWNoIHRyYW5zZm9ybWVkIHZhcmlhYmxlcyBhcmUgbm90IHVzZWQgaW4gdGhlIGZvbGxvd2luZyBhbmFseXNlcy4gIEFzIGRvbmUgYWJvdmUsIHdlIHNob3cgaG93IHRvIGltcGxlbWVudCB0aGlzIHN0ZXAgYnkgdXNpbmcgYm90aCBgYmFzZWAgUiBhbmQsIGFsdGVybmF0aXZlbHksIHRoZSBgdGlkeXZlcnNlYCBzeW50YXguDQoNCiMjIyBCYXNlIFINCg0KV2l0aCBgYmFzZWAgUiwgbGFnZ2luZyBpcyBpbXBsZW1lbnRlZCB3aXRoIGEgZm9yLWxvb3AgdGhhdCBwYXN0ZXMgdGhlIHZhcmlhYmxlIHZhbHVlIGZyb20gdGhlIHByZXZpb3VzIHJvdyBpZiB0aGUgdmFsdWVzIG9mIGJvdGggcGFydGljaXBhbnQgKGkuZS4sIGBJRGApIGFuZCB0aW1lIGlkZW50aWZpZXJzIChpLmUuLCBgZGF5YCkgYXJlIGVxdWFsIHRvIHRob3NlIG9mIHRoZSBwcmV2aW91cyByb3cuIFNpbWlsYXJseSwgbGVhZGluZyBpcyBpbXBsZW1lbnRlZCB3aXRoIGEgZm9yLWxvb3AgdGhlIHBhc3RlcyB0aGUgdmFyaWFibGUgdmFsdWUgZnJvbSB0aGUgZm9sbG93aW5nIHJvdyBpZiB0aGUgcGFydGljaXBhbnQgYW5kIHRpbWUgdmFsdWVzIGFyZSBlcXVhbCB0byB0aG9zZSBvZiB0aGUgZm9sbG93aW5nIHJvdy4gSGVyZSwgd2Ugc2hvdyBhbiBleGFtcGxlIHdpdGggdGhlIHZhcmlhYmxlIGBURGAuDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBzYXZpbmcgZGF0YSBhcyBhbiBhbHRlcm5hdGl2ZSBkYXRhc2V0DQppbGRfYmFzZVIgPC0gaWxkWyxjKCJJRCIsImRheSIsIlREIildDQoNCiMgbGFnZ2luZyBURCB2YXJpYWJsZQ0KZm9yKGkgaW4gMjpucm93KGlsZCkpeyAjIGZvciBlYWNoIHJvdyBpbiB0aGUgaWxkIGRhdGFzZXQNCiAgaWYoaWxkW2ksIklEIl0gPT0gaWxkW2ktMSwiSUQiXSAmICMgSUYgc2FtZSBJRCBvZiB0aGUgcHJldmlvdXMgcm93Li4uIA0KICAgICBpbGRbaSwiZGF5Il0gPT0gaWxkW2ktMSwiZGF5Il0peyAjIC4uLkFORCBzYW1lIGRheSBvZiB0aGUgcHJldmlvdXMgcm93Li4uDQogICAgaWxkX2Jhc2VSW2ksIlRELmxhZyJdIDwtIGlsZFtpLTEsIlREIl0gIyAuLi5wYXN0ZSB0aGUgdmFsdWUgb2YgdGhlIHByZXZpb3VzIHJvdw0KICB9fQ0KDQojIGxlYWRpbmcgVEQgdmFyaWFibGUNCmZvcihpIGluIDE6KG5yb3coaWxkKS0xKSl7ICMgZm9yIGVhY2ggcm93IGluIHRoZSBpbGQgZGF0YXNldA0KICBpZihpbGRbaSwiSUQiXSA9PSBpbGRbaSsxLCJJRCJdICYgIyBJRiBzYW1lIElEIG9mIHRoZSBuZXh0IHJvdy4uLiANCiAgICAgaWxkW2ksImRheSJdID09IGlsZFtpKzEsImRheSJdKXsgIyAuLi5BTkQgc2FtZSBkYXkgb2YgdGhlIG5leHQgcm93Li4uDQogICAgaWxkX2Jhc2VSW2ksIlRELmxlYWQiXSA8LSBpbGRbaSsxLCJURCJdICMgLi4ucGFzdGUgdGhlIHZhbHVlIG9mIHRoZSBuZXh0IHJvdw0KICB9fQ0KDQojIHNob3dpbmcgb3JpZ2luYWwsIGxhZ2dlZCwgYW5kIGxlZCB2YXJpYWJsZQ0KaWxkX2Jhc2VSWyxjKCJJRCIsImRheSIsIlREIiwiVEQubGFnIiwiVEQubGVhZCIpXQ0KYGBgDQoNCjxicj4NCg0KIyMjIFRpZHl2ZXJzZQ0KDQpIZXJlLCB3ZSByZXBsaWNhdGUgdGhlIHNhbWUgb3BlcmF0aW9ucyBpbiB0aHJlZSBhbHRlcm5hdGl2ZSB3YXlzIGJhc2VkIG9uIHRoZSBgdGlkeXZlcnNlYCBzeW50YXggKHNlZSBbV2lja2hhbSBldCBhbC4sIDIwMjNdKCNyZWYpKSwgYWxsIG9mIHdoaWNoIHVzZXMgdGhlIGBsYWdgIGFuZCB0aGUgYGxlYWRgLCBmdW5jdGlvbnMgd2l0aGluIHRoZSBgbXV0YXRlYCBmdW5jdGlvbi4gSW4gb3B0aW9uIEEsIEluIG9wdGlvbiBBLCB3ZSB1c2UgdGhlIHBpcGUgb3BlcmF0b3IgYCU+JWAgdG8gY29uY2F0ZW5hdGUgb3BlcmF0aW9ucywgdGhlIGBncm91cF9ieWAgZnVuY3Rpb24gdG8gZ3JvdXAgb3BlcmF0aW9ucyBieSBwYXJ0aWNpcGFudCBgSURgIGFuZCBgZGF5YCwgYW5kIHRoZSBgbXV0YXRlYCwgYGxhZ2AsIGFuZCBgbGVhZGAgZnVuY3Rpb25zIHRvIHNwZWNpZnkgd2hpY2ggb3BlcmF0aW9ucyBzaG91bGQgYmUgYXBwbGllZCAoaS5lLiwgbGFnZ2luZyBhbmQgbGVhZGluZyBieSAqbiogPSAxIHdpdGhpbiB0aGUgc2FtZSBkYXkgYW5kIHRoZSBwYXJ0aWNpcGFudCkuIEluIG9wdGlvbiBCLCB3ZSBkaXJlY3RseSB1c2UgdGhlIGBtdXRhdGVgIGZ1bmN0aW9uIHRvIHNwZWNpZnkgYm90aCB0aGUgb3BlcmF0aW9ucyB0byBiZSBhcHBsaWVkIGFuZCB0aGUgdHdvIGdyb3VwaW5nIHZhcmlhYmxlcyAoc3BlY2lmaWVkIHdpdGggdGhlIGFyZ3VtZW50IGAuYnlgKS4gRmluYWxseSwgb3B0aW9uIEMgaXMgYW4gZXh0ZW5zaW9uIG9mIG9wdGlvbiBCIHdoZXJlIHdlIHVzZSB0aGUgYGFjcm9zc2AgZnVuY3Rpb24gdG8gcmVwZWF0IHRoZSBvcGVyYXRpb25zIHNwZWNpZmllZCBpbiB0aGUgYC5mbnNgIGFyZ3VtZW50IGFjcm9zcyBhbGwgdGhlIGNvbHVtbnMgc3BlY2lmaWVkIGluIHRoZSBgLmNvbHNgIGFyZ3VtZW50IG9mIHRoZSBgbXV0YXRlYCBmdW5jdGlvbi4gSW4gdGhpcyB3YXksIGl0IGlzIHBvc3NpYmxlIHRvIGF2b2lkIG1hbnVhbGx5IHJld3JpdGluZyB0aGUgc2FtZSBvcGVyYXRpb25zIGZvciBlYWNoIHZhcmlhYmxlLCBhcyBpbiBvcHRpb24gQSBhbmQgQi4gDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBsb2FkaW5nIHRpZHl2ZXJzZSBwYWNrYWdlIGNvbGxlY3Rpb24NCmxpYnJhcnkodGlkeXZlcnNlKQ0KDQojIG9wdGlvbiBBOiBtdXRhdGUgYW5kIGdyb3VwX2J5DQppbGRfdGlkeXZlcnNlX0EgPC0gDQogIGlsZCAlPiUNCiAgZ3JvdXBfYnkoSUQsZGF5KSAlPiUgIyBncm91cGluZyBvcGVyYXRpb25zIGJ5IGNsdXN0ZXIgdmFyaWFibGUgIklEIg0KICBtdXRhdGUoVEQubGFnID0gbGFnKFRELCBuID0gMSksICMgbGFnZ2luZyB0aGUgVEQgdmFyaWFibGUNCiAgICAgICAgIFRELmxlYWQgPSBsZWFkKFRELCBuID0gMSkpICMgbGVhZGluZyB0aGUgVEQgdmFyaWFibGVyaWFibGUNCmlsZF90aWR5dmVyc2VfQVssYygiSUQiLCJkYXkiLCJURCIsIlRELmxhZyIsIlRELmxlYWQiKV0gIyBzaG93aW5nIGRhdGENCg0KIyBvcHRpb24gQjogbXV0YXRlIHdpdGggIi5ieSINCmlsZF90aWR5dmVyc2VfQiA8LSANCiAgbXV0YXRlKGlsZCwNCiAgICAgICAgIFRELmxhZyA9IGxhZyhURCwgbiA9IDEpLCAjIGxhZ2dpbmcgdGhlIFREIHZhcmlhYmxlDQogICAgICAgICBURC5sZWFkID0gbGVhZChURCwgbiA9IDEpLCAjIGxlYWRpbmcgdGhlIFREIHZhcmlhYmxlDQogICAgICAgICAuYnkgPSBjKElELGRheSkpICMgZ3JvdXBpbmcgb3BlcmF0aW9ucyBieSBjbHVzdGVyIHZhcmlhYmxlICJJRCINCmlsZF90aWR5dmVyc2VfQlssYygiSUQiLCJkYXkiLCJURCIsIlRELmxhZyIsIlRELmxlYWQiKV0gIyBzaG93aW5nIGRhdGENCg0KIyBvcHRpb24gQzogcmVwZWF0IG9wdGlvbiBCIG92ZXIgbXVsdGlwbGUgY29sdW1ucyB1c2luZyB0aGUgImFjcm9zcyIgY29tbWFuZA0KaWxkX3RpZHl2ZXJzZV9DIDwtDQogIG11dGF0ZShpbGQsDQogICAgICAgICBhY3Jvc3MoDQogICAgICAgICAgICMgc2VsZWN0aW5nIGFsbCB0aGUgY29sdW1ucyBvbiB3aGljaCByZXBlYXRpbmcgdGhlIG9wZXJhdGlvbnMNCiAgICAgICAgICAgLmNvbHMgPSBjKCJURCIsIlRDIiwiTlYiKSwgDQogICAgICAgICAgIC5mbnMgPSBsaXN0KCAjIGxpc3Qgb2Ygb3BlcmF0aW9ucyB0byBiZSByZXBlYXRlZA0KICAgICAgICAgICAgIGxhZyA9fiBsYWcoLngsIG4gPSAxKSwgIyBsYWdnaW5nIHRoZSBURCB2YXJpYWJsZQ0KICAgICAgICAgICAgIGxlYWQgPX4gbGVhZCgueCwgbiA9IDEpICkpLCAjIGxlYWRpbmcgdGhlIFREIHZhcmlhYmxlDQogICAgICAgICAuYnkgPSBjKElELGRheSkpICMgZ3JvdXBpbmcgb3BlcmF0aW9ucyBieSBjbHVzdGVyIHZhcmlhYmxlICJJRCINCmlsZF90aWR5dmVyc2VfQ1ssYygiSUQiLCJkYXkiLCJURCIsIlREX2xhZyIsIlREX2xlYWQiLCJUQyIsIlRDX2xhZyIsIlRDX2xlYWQiKV0gIyBzaG93aW5nIGRhdGENCmBgYA0KDQo8YnI+DQoNCiMgMi4gRGF0YSBhbmFseXNpcyB7I2FuYWx5c2VzfQ0KDQojIyAyLjEuIERlc2NyaXB0aXZlIHN0YXRpc3RpY3Mgey50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHN9DQoNCkhlcmUsIHdlIGNvbXB1dGUgZGVzY3JpcHRpdmUgc3RhdGlzdGljcywgbmFtZWx5IHRoZSBudW1iZXIgb2YgaW5jbHVkZWQgb2JzZXJ2YXRpb25zIGFuZCBwYXJ0aWNpcGFudHMsIG1lYW4sIFNELCBhbmQgZnJlcXVlbmNpZXMgb2YgZWFjaCBpbmNsdWRlZCB2YXJpYWJsZXMsIHRoZSBJQ0MoMSkgb2YgdGltZS12YXJ5aW5nIHZhcmlhYmxlcywgYW5kIHRoZSBsZXZlbC1zcGVjaWZpYyBjb3JyZWxhdGlvbnMgYW1vbmcgdGhlIGluY2x1ZGVkIHF1YW50aXRhdGl2ZSB2YXJpYWJsZXMuIFRvIGlsbHVzdHJhdGUgaG93IHRoZSBzYW1lIG91dHB1dCBjYW4gYmUgb2J0YWluZWQgaW4gbXVsdGlwbGUgd2F5cywgd2UgY29tcHV0ZSBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIGJvdGggdXNpbmcgYGJhc2VgIFIgc3ludGF4IGFuZCwgYWx0ZXJuYXRpdmVseSwgdXNpbmcgdGhlIGBwc3ljaGAgcGFja2FnZS4NCg0KIyMjIEJhc2UgUg0KDQpXaXRoIGBiYXNlYCBSLCB0aGUgbWVhbiBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHF1YW50aXRhdGl2ZSB2YXJpYWJsZXMgYW5kIHRoZSBmcmVxdWVuY3kgb2YgY2F0ZWdvcmljYWwgdmFyaWFibGVzIGFyZSBjb21wdXRlZCB3aXRoaW4gYSBmb3ItbG9vcC4gQSBzZWNvbmQgZm9yLWxvb3AgaXMgdGhlbiB1c2VkIHRvIGV4dHJhY3QgdGhlIHZhcmlhbmNlIGNvbXBvbmVudHMgZnJvbSBpbnRlcmNlcHQtb25seSBsaW5lYXIgbWl4ZWQtZWZmZWN0cyByZWdyZXNzaW9uIG1vZGVscywgd2hpY2ggYXJlIHVzZWQgdG8gZXN0aW1hdGUgdGhlIElDQygxKS4gRmluYWxseSwgd2UgdXNlIHRoZSBgY29yYCBmdW5jdGlvbiB0byBjb21wdXRlIGFuZCBtZXJnZSB3aXRoaW4tIGFuZCBiZXR3ZWVuLWluZGl2aWR1YWwgY29ycmVsYXRpb25zLg0KDQpgYGB7ciBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIG51bWJlciBvZiBpbmNsdWRlZCBvYnNlcnZhdGlvbnMNCmNhdCgiTGV2ZWwgMToiLG5yb3coaWxkKSwib2JzZXJ2YXRpb25zOyBMZXZlbCAyOiIsbnJvdyhpbGRbIWR1cGxpY2F0ZWQoaWxkJElEKSxdKSwicGFydGljaXBhbnRzIikNCg0KIyBzZWxlY3RpbmcgdmFyaWFibGUgbmFtZXMNClZhck5hbWVzIDwtIGMoIk5WIiwiVEQiLCJUQyIpDQoNCiMgY29tcHV0aW5nIG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbg0KZGVzYyA8LSBjKCkgIyBlbXB0eSB2ZWN0b3IgdG8gYmUgZmlsbGVkIHdpdGggZGVzY3JpcHRpdmUgc3RhdHMNCmZvcihWYXJOYW1lIGluIFZhck5hbWVzKXsgIyBmb3IgZWFjaCB0aW1lLXZhcnlpbmcgdmFyaWFibGUuLi4NCiAgZGVzY1tWYXJOYW1lXSA8LSAjIC4uLmNvbXB1dGluZyBtZWFuIGFuZCBTRCBhbmQgcGFzdGluZyB0aGVtIHRvZ2V0aGVyDQogICAgcGFzdGUwKHJvdW5kKG1lYW4oaWxkWyxWYXJOYW1lXSksMiksDQogICAgICAgICAgICIgKCIscm91bmQoc2QoaWxkWyxWYXJOYW1lXSksMiksIikiKSB9IA0KZGVzY1siYWdlIl0gPC0gIyBzYW1lIHRoaW5nIGZvciBhZ2UgYnV0IGJhc2VkIG9uIHRoZSB3aWRlLWZvcm0gZGF0YXNldA0KICBwYXN0ZTAocm91bmQobWVhbihwcmVscXMkYWdlKSwyKSwgDQogICAgICAgICAiICgiLHJvdW5kKHNkKHByZWxxcyRhZ2UpLDIpLCIpIikgDQpkZXNjWyJnZW5kZXIiXSA8LSAjIGZyZXF1ZW5jeSBhbmQgJSBvZiBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgKGdlbmRlcikNCiAgcGFzdGUwKHRhYmxlKHByZWxxcyRnZW5kZXIpWzFdLCIgRiAoIiwNCiAgICAgICAgIHJvdW5kKDEwMCpwcm9wLnRhYmxlKHRhYmxlKHByZWxxcyRnZW5kZXIpKSwyKSwiJSkiKQ0KDQojIGNvbXB1dGluZyBJQ0MoMSkgYmFzZWQgb24gdmFyaWFuY2UgZGVjb21wb3NpdGlvbg0KbGlicmFyeShsbWU0KSAjIGxvYWRpbmcgcGFja2FnZSB0byBmaXQgbGluZWFyIG1peGVkLWVmZmVjdHMgcmVncmVzc2lvbiBtb2RlbHMNCmljYyA8LSBjKCkgIyBlbXB0eSB2ZWN0b3IgdG8gYmUgZmlsbGVkIHdpdGggSUNDIHZhbHVlcw0KZm9yKFZhck5hbWUgaW4gVmFyTmFtZXMpeyAjIGZvcmVhY2ggdGltZS12YXJ5aW5nIHZhcmlhYmxlLi4NCiAgZml0IDwtIGxtZXIoYXMuZm9ybXVsYShwYXN0ZShWYXJOYW1lLCJ+ICgxfElEKSIpKSwgZGF0YSA9IGlsZCkgIyBmaXR0aW5nIG51bGwgbXVsdGlsZXZlbCBtb2RlbA0KICB0YXUwMCA8LSBzdW1tYXJ5KGZpdCkkdmFyY29yJElEW1sxXV0gIyB2YXJpYW5jZSBvZiB0aGUgcmFuZG9tIGludGVyY2VwdA0KICBzaWdtYTIgPC0gc3VtbWFyeShmaXQpJHNpZ21hXjIgIyByZXNpZHVhbCB2YXJpYW5jZQ0KICBpY2MgPC0gYyhpY2MsIFZhck5hbWUgPSByb3VuZCh0YXUwMC8odGF1MDAgKyBzaWdtYTIpLDIpKSAjIElDQyA9IHRhdTAwLyh0YXUwMCtzaWdtYTIpDQogIH0NCg0KIyBjb21wdXRpbmcgbGV2ZWwtc3BlY2lmaWMgY29ycmVsYXRpb25zIGFtb25nIHRpbWUtdmFyeWluZyB2YXJpYWJsZXMNCmNvcjEgPC0gcm91bmQoY29yKGlsZFsscGFzdGUwKFZhck5hbWVzLCJ3IildKSwyKSAjIGxldmVsIDEgKGNsdXN0ZXItbWVhbi1jZW50ZXJlZCkNCmNvcjIgPC0gcm91bmQoY29yKGlsZFshZHVwbGljYXRlZChpbGQkSUQpLHBhc3RlMChWYXJOYW1lcywiYiIpXSksMikgIyBsZXZlbCAyIChjbHVzdGVyIG1lYW5zKQ0KY29yMVtsb3dlci50cmkoY29yMSldIDwtIGNvcjJbbG93ZXIudHJpKGNvcjIpXSAjIG1lcmdpbmcgdGhlIHR3byBtYXRyaWNlcw0Kcm93bmFtZXMoY29yMSkgPC0gY29sbmFtZXMoY29yMSkgPC0gVmFyTmFtZXMgIyBhZGRpbmcgdmFyaWFibGUgbGFiZWxzDQoNCiMgYWRkaW5nIGxldmVsLTIgY29ycmVsYXRpb25zIHdpdGggYWdlICsgZW1wdHkgcm93IGZvciBnZW5kZXINCmNvcjEgPC0gcmJpbmQoY29yMSwNCiAgICAgICAgICAgICAgY29yKHg9aWxkWyFkdXBsaWNhdGVkKGlsZCRJRCksYyhwYXN0ZTAoVmFyTmFtZXMsImIiKSwiYWdlIildLClbNCwxOjNdLA0KICAgICAgICAgICAgICBtYXRyaXgocmVwKE5BLDMpLG5yb3c9MSkpDQpyb3duYW1lcyhjb3IxKVs0OjVdIDwtIGMoImFnZSIsImdlbmRlciIpDQoNCiMgam9pbmluZyBhbmQgcHJpbnRpbmcgZGVzY3JpcHRpdmUgc3RhdHMsIElDQywgYW5kIGNvcnJlbGF0aW9ucw0KY2JpbmQoZGF0YS5mcmFtZShEZXNjID0gZGVzYywgSUNDID0gYyhpY2MsIE5BLCBOQSkpLCByb3VuZChjb3IxLCAyKSkNCmBgYA0KDQo8YnI+DQoNCiMjIyBwc3ljaA0KDQpIZXJlLCB3ZSBpbGx1c3RyYXRlIGhvdyB0aGUgc2FtZSBvcGVyYXRpb25zIGNhbiBiZSBvcHRpbWl6ZWQgd2l0aCB0aGUgYHBzeWNoYCBwYWNrYWdlLiBGaXJzdCwgd2UgdXNlIHRoZSBgZGVzY3JpYmVgIGZ1bmN0aW9uIHRvIGNvbXB1dGUgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMsIG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBvZiBlYWNoIHF1YW50aXRhdGl2ZSB2YXJpYWJsZS4gU2Vjb25kLCB3ZSB1c2UgdGhlIGBzdGF0QnlgIGZ1bmN0aW9uIHRvIGNvbXB1dGUgSUNDcygxKSBmb3IgZWFjaCB0aW1lLXZhcnlpbmcgdmFyaWFibGUgYW5kIGxldmVsLXNwZWNpZmljIGNvcnJlbGF0aW9ucy4gRmluYWxseSwgd2Ugc2hvdyBob3cgdG8gZXh0cmFjdCBhbmQgcmVwb3J0IHRoZSBzaWduaWZpY2FuY2UgbGV2ZWwgb2YgZWFjaCBjb3JyZWxhdGlvbiBjb2VmZmljaWVudC4NCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQojIGxvYWRpbmcgcHN5Y2ggcGFja2FnZQ0KbGlicmFyeShwc3ljaCkNCg0KIyBjb21wdXRpbmcgbnVtYmVyIG9mIG9ic2VydmF0aW9ucywgbWVhbiBhbmQgc2QNCmRlc2MgPC0gcmJpbmQoZGVzY3JpYmUoaWxkWyxjKCJOViIsIlREIiwiVEMiKV0pWyxjKCJuIiwibWVhbiIsInNkIildLCAjIHRpbWUtdmFyeWluZw0KICAgICAgICAgICAgICBkZXNjcmliZShwcmVscXNbLCJhZ2UiXSlbLGMoIm4iLCJtZWFuIiwic2QiKV0pICMgdGltZS1pbnZhcmlhbnQNCg0KIyBjb21wdXRpbmcgSUNDKDEpDQppY2MgPC0gYyhyb3VuZChzdGF0c0J5KGlsZFssYygiTlYiLCJURCIsIlRDIildLGdyb3VwPWlsZCRJRCkkSUNDMVsxOjNdLDIpKSANCg0KIyBjb21wdXRpbmcgbGV2ZWwtc3BlY2lmaWMgY29ycmVsYXRpb25zDQpjb3JzIDwtIHBzeWNoOjpzdGF0c0J5KGlsZFssYygiTlYiLCJURCIsIlRDIiwiYWdlIildLGdyb3VwPWlsZCRJRCkNCmNvcnMkcndnW2xvd2VyLnRyaShjb3JzJHJ3ZyldIDwtIGNvcnMkcmJnW2xvd2VyLnRyaShjb3JzJHJiZyldICMgbWVyZ2luZyBsdi0xICYgbHYtMiBjb3JyZWxhdGlvbnMNCg0KIyBqb2luaW5nIGFuZCBwcmludGluZyBkZXNjcmlwdGl2ZSBzdGF0cywgSUNDLCBhbmQgY29ycmVsYXRpb25zDQpkZXNjIDwtIGNiaW5kKGRhdGEuZnJhbWUoRGVzYyA9IGRlc2MsIElDQyA9IGMoaWNjLCBOQSkpLCByb3VuZChjb3JzJHJ3Z1ssMTozXSwgMikpDQpyb3duYW1lcyhkZXNjKSA8LSBjKCJOViIsIlREIiwiVEMiLCJhZ2UiKSAjIHJlbmFtaW5nIHJvd3MNCmNvbG5hbWVzKGRlc2MpIDwtIGMoIm4iLCJtZWFuIiwiU0QiLCJJQ0MiLCJOViIsIlREIiwiVEMiKSAjIHJlbmFtaW5nIGNvbHVtbnMNCmRlc2MgIyBwcmludGluZyBkZXNjcmlwdGl2ZSBzdGF0cw0KDQojIG9wdGlvbmFsOiBhZGRpbmcgYXN0ZXJpc2tzIGZvciBwLXZhbHVlcw0KY29ycyRwd2dbbG93ZXIudHJpKGNvcnMkcHdnKV0gPC0gY29ycyRwYmdbbG93ZXIudHJpKGNvcnMkcGJnKV0gIyBtZXJnaW5nIGx2LTEgJiBsdi0yIHAtdmFsdWVzDQpwIDwtIG1hdHJpeChucm93PTQsbmNvbD0zKSAjIGNyZWF0aW5nIGVtcHR5IG1hdHJpeCB0byBiZSBmaWxsZWQgd2l0aCBzaWduaWZpY2FuY2UgbGV2ZWxzDQpmb3IoaSBpbiAxOjQpew0KICBmb3IoaiBpbiAxOjMpew0KICAgIGlmKCFpcy5uYShjb3JzJHB3Z1tpLGpdKSAmIGNvcnMkcHdnW2ksal0gIT0gMSl7DQogICAgICBkZXNjW2ksais0XSA8LSBwYXN0ZTAoZGVzY1tpLGorNF0sICMgYWRkaW5nIGFzdGVyaXNrcyB0byBjb3JyZWxhdGlvbiBjb2VmZmljaWVudHMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoY29ycyRwd2dbaSxqXSA8IC4wMDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIqKioiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoY29ycyRwd2dbaSxqXSA8IC4wMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIqKiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoY29ycyRwd2dbaSxqXSA8IC4wNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiKiIsIiIpKSkpIH19fQ0KZGVzYyAjIHByaW50aW5nIGRlc2NyaXB0aXZlIHN0YXRzDQpgYGANCg0KPGJyPg0KDQojIyAyLjIuIFJlZ3Jlc3Npb24gbW9kZWxzDQoNCkhlcmUsIHdlIGZpdCBhbmQgcHJpbnQgdGhlIHR3byBpbGx1c3RyYXRpdmUgbW9kZWxzIHRlc3RpbmcgSkRDIGh5cG90aGVzZXMuIFRoaXMgaXMgZG9uZSBieSBpbmNsdWRpbmcgY2x1c3Rlci1tZWFuLWNlbnRlcmVkIHRhc2sgZGVtYW5kcyBgVER3YCBhbmQgdGFzayBjb250cm9sIGBUQ3dgIGFuZCB0aGVpciBsZXZlbC0xIGludGVyYWN0aW9uIGluIE1vZGVsIDEsIHdoZXJlYXMgbW9kZWwgMiBpbmNsdWRlcyBhbmQgdGVzdHMgdGhlIGNyb3NzLWxldmVsIGludGVyYWN0aW9uIGJldHdlZW4gY2x1c3Rlci1tZWFuLWNlbnRlcmVkIHRhc2sgZGVtYW5kcyBgVER3YCBhbmQgdGhlIGNsdXN0ZXIgbWVhbnMgb2YgdGFzayBjb250cm9sIGBUQ2JgLiBJbiBib3RoIG1vZGVscywgd2UgaW5jbHVkZSBgYWdlYCBhbmQgYGdlbmRlcmAgYXMgbGV2ZWwtMiBjb3ZhcmlhdGVzIGFuZCBhIHJhbmRvbSBzbG9wZSBmb3IgdGFzayBkZW1hbmRzLiBCb3RoIG1vZGVscyBhcmUgZml0dGVkIHdpdGggdGhlIFJFTUwgZXN0aW1hdG9yIChzZWUgW01jTmVpc2gsIDIwMTddKCNyZWYpKS4NCmBgYHtyIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0NCiMgbG9hZGluZyByZXF1aXJlZCBwYWNrYWdlcw0KbGlicmFyeShsbWU0KTsgbGlicmFyeShzalBsb3QpDQpgYGANCmBgYHtyIGZpZy53aWR0aD05LGZpZy5oZWlnaHQ9M30NCiMgZml0dGluZyBtb2RlbHMNCmZpdDEgPC0gbG1lcihOViB+IFREdyAqIFRDdyArIGFnZSArIGdlbmRlciArIChURHd8SUQpLCBkYXRhID0gaWxkKQ0KZml0MiA8LSBsbWVyKE5WIH4gVER3ICogVENiICsgYWdlICsgZ2VuZGVyICsgKFREd3xJRCksIGRhdGEgPSBpbGQpDQoNCiMgcHJpbnRpbmcgb3V0cHV0IHRhYmxlDQp0YWJfbW9kZWwoZml0MSwgZml0MiwNCiAgICAgICAgICBzaG93LnNlID0gVFJVRSwgY29sbGFwc2Uuc2UgPSBUUlVFLCBwLnZhbCA9ICJ3YWxkIiwgIyBXYWxkIGFwcHJveGltYXRpb24NCiAgICAgICAgICBzaG93LmNpID0gRkFMU0UsIHNob3cuaWNjID0gRkFMU0UpDQpgYGANCg0KTm90ZSB0aGF0IHRoZSBtYXJnaW5hbCBhbmQgY29uZGl0aW9uYWwgJFJeMiQgYXJlIGVzdGltYXRlcyBvZiB0aGUgcHJvcG9ydGlvbiBvZiBuZWdhdGl2ZSB2YWxlbmNlIHZhcmlhbmNlIGV4cGxhaW5lZCBieSBmaXhlZCBlZmZlY3RzIG9ubHkgYW5kIGJ5IGJvdGggZml4ZWQgYW5kIHJhbmRvbSBlZmZlY3RzLCByZXNwZWN0aXZlbHkuDQoNCjxicj4NCg0KRmluYWxseSwgd2UgcGxvdCB0aGUgZXN0aW1hdGVkIGludGVyYWN0aW9ucy4NCmBgYHtyIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0NCiMgbG9hZGluZyByZXF1aXJlZCBwYWNrYWdlcw0KbGlicmFyeShnZ3Bsb3QyKTsgbGlicmFyeShncmlkRXh0cmEpDQpgYGANCmBgYHtyIGZpZy53aWR0aD05LGZpZy5oZWlnaHQ9MyxtZXNzYWdlPUZBTFNFfQ0KIyBzZXR0aW5nIGdyYXBoaWNhbCBwYXJhbWV0ZXJzDQpzZF90YzEgPC0gcm91bmQoc2QoaWxkJFRDdyksMikgIyBjb21wdXRpbmcgVEMgc3RhbmRhcmQgZGV2LiBhdCBsZXZlbCAxDQptZWFuX3RjMiA8LSByb3VuZChtZWFuKG1lYW5zJFRDYiksMikgIyBjb21wdXRpbmcgbWVhbiBUQyBhdCBsZXZlbCAyDQpzZF90YzIgPC0gcm91bmQoc2QobWVhbnMkVENiKSwyKSAjIGNvbXB1dGluZyBUQyBzdGFuZGFyZCBkZXYuIGF0IGxldmVsIDINCmxhYnMgPC0gYygiLTEgU0QiLCIrMSBTRCIpICMgc2V0dGluZyBsZWdlbmQgbGFiZWxzDQpjb2xzIDwtIGMoImJsYWNrIiwiIzY2NjY2NiIpICMgc2V0dGluZyBjb2xvcnMNCmxpbnMgPC0gYygic29saWQiLCJkYXNoZWQiKSAjIHNldHRpbmcgbGluZSB0eXBlcw0KDQojIHBsb3R0aW5nDQpwIDwtIGdyaWQuYXJyYW5nZSgNCiAgIyBNb2RlbCAxIChUQ3cgKy8tIDEgU0QpDQogIHBsb3RfbW9kZWwoZml0MSx0eXBlPSJwcmVkIix0ZXJtcz1jKCJURHciLHBhc3RlMCgiVEN3IFsiLC1zZF90YzEsIiwiLHNkX3RjMSwiXSIpKSkgKyANCiAgICBzY2FsZV9jb2xvcl9tYW51YWwobGFiZWxzPWxhYnMsdmFsdWVzPWNvbHMpICsNCiAgICBzY2FsZV9saW5ldHlwZV9tYW51YWwobGFiZWxzPWxhYnMsdmFsdWVzPWxpbnMpICsgDQogICAgc2NhbGVfZmlsbF9tYW51YWwobGFiZWxzPWxhYnMsdmFsdWVzPWNvbHMpICsgZ2d0aXRsZSgiIikgKyANCiAgICB4bGFiKCJUYXNrIGRlbWFuZCAod2l0aGluKSIpICsgeWxhYigiTmVnYXRpdmUgdmFsZW5jZSIpICsNCiAgICBndWlkZXMoY29sb3I9Z3VpZGVfbGVnZW5kKHRpdGxlPSJUYXNrIENvbnRyb2xcbih3aXRoaW4pIikpLA0KICAjIE1vZGVsIDIgKE1lYW4gVENiICsvLSAxIFNEKQ0KICBwbG90X21vZGVsKGZpdDIsdHlwZT0icHJlZCIsDQogICAgICAgICAgICAgdGVybXM9YygiVER3IixwYXN0ZTAoIlRDYiBbIixtZWFuX3RjMi1zZF90YzEsIiwiLG1lYW5fdGMyK3NkX3RjMSwiXSIpKSkgKw0KICAgIHNjYWxlX2NvbG9yX21hbnVhbChsYWJlbHM9bGFicyx2YWx1ZXM9Y29scykgKw0KICAgIHNjYWxlX2xpbmV0eXBlX21hbnVhbChsYWJlbHM9bGFicyx2YWx1ZXM9bGlucykgKyANCiAgICBzY2FsZV9maWxsX21hbnVhbChsYWJlbHM9bGFicyx2YWx1ZXM9Y29scykgKyBnZ3RpdGxlKCIiKSArIA0KICAgIHhsYWIoIlRhc2sgZGVtYW5kICh3aXRoaW4pIikgKyB5bGFiKCJOZWdhdGl2ZSB2YWxlbmNlIikgKw0KICAgIGd1aWRlcyhjb2xvcj1ndWlkZV9sZWdlbmQodGl0bGU9IlRhc2sgY29udHJvbFxuKGJldHdlZW4pIikpLCBucm93PTEpDQoNCiMgZXhwb3J0aW5nIGZpZ3VyZQ0KZ2dzYXZlKCJmaWcyLnBuZyIsIHBsb3QgPSBwLCBkcGkgPSAzMDApDQpgYGANCg0KPGJyPg0KDQojIDMuIE11bHRpdmVyc2UgYXBwcm9hY2gNCg0KSGVyZSwgd2UgaW50ZWdyYXRlIHRoZSBjb2RlIHByb3ZpZGVkIGZvciBlYWNoIHN0ZXAgaW50byBhIHVuaWZpZWQgZnVuY3Rpb24gYGlsZC5tYW5pcGAgdG8gaWxsdXN0cmF0ZSBob3cgcmVzdWx0cyBtaWdodCBjaGFuZ2UgYmFzZWQgb24gZGF0YSBtYW5pcHVsYXRpb24gY2hvaWNlcy4gTm90ZSB0aGF0IHNvbWUgb2YgdGhlIGZ1bmN0aW9uIGFyZ3VtZW50cyBhcmUgc2V0IGJ5IGRlZmF1bHQgYXMgcmVxdWlyZWQgYnkgb3VyIGlsbHVzdHJhdGl2ZSBleGFtcGxlLg0KDQo8ZGV0YWlscz48c3VtbWFyeT5zaG93IGBpbGQubWFuaXBgPC9zdW1tYXJ5Pg0KPHA+DQpgYGB7ciB9DQojJyBAdGl0bGUgSW50ZW5zaXZlIGxvbmdpdHVkaW5hbCBkYXRhIG1hbmlwdWxhdGlvbg0KIycgQHBhcmFtIGxvbmcgPSBsb25nLWZvcm0gZGF0YXNldCAoZGF0YS5mcmFtZSkNCiMnIEBwYXJhbSB3aWRlID0gd2lkZS1mb3JtIGRhdGFzZXQgKGRhdGEuZnJhbWUpDQojJyBAcGFyYW0gY2x1c3RlciA9IG5hbWUgb2YgdGhlIGNsdXN0ZXIgdmFyaWFibGUgaWRlbnRpZnlpbmcgcGFydGljaXBhbnRzIChjaGFyYWN0ZXIpDQojJyBAcGFyYW0gbG9uZy5yZXNwVGltZSA9IG5hbWUgb2YgdGhlIHRpbWUgdmFyaWFibGUgaW4gdGhlIGxvbmctZm9ybSBkYXRhc2V0IChjaGFyYWN0ZXIpDQojJyBAcGFyYW0gcmVzcFRpbWUuZm9ybWF0ID0gdGltZSBmb3JtYXQgdXNlZCBieSB0aGUgbG9uZy5yZXNwVGltZSB2YXJpYWJsZSAoY2hhcmFjdGVyKSAoc2VlID9zdHJwdGltZSkNCiMnIEBwYXJhbSBzY2hlZHVsZWRUaW1lcyA9IGxpc3Qgb2YgdGhyZWUtZWxlbWVudCBjaGFyYWN0ZXIgdmVjdG9ycyByZXBvcnRpbmcgdGhlIG1pbmltdW0sIGNlbnRyYWwsIGFuZCBtYXhpbXVtIHRpbWUgZm9yIGVhY2ggc2NoZWR1bGVkIG1lYXN1cmVtZW50IHVzaW5nIHRoZSBzYW1lIHRpbWUgZm9ybWF0IHNldCBpbiB0aGUgc2NoZWR1bGVkVGltZXMuZm9ybWF0IGFyZ3VtZW50DQojJyBAcGFyYW0gc2NoZWR1bGVkVGltZXMuZm9ybWF0ID0gdGltZSBmb3JtYXQgKHdpdGhvdXQgZGF0ZSkgdXNlZCBpbiB0aGUgc2NoZWR1bGVkVGltZXMgYXJndW1lbnQgKGNoYXJhY3RlcikgKGRlZmF1bHQgIiVIOiVNOiVTIikNCiMnIEBwYXJhbSBsb25nLnZhcmlhYmxlcyA9IGxpc3Qgb2YgdmFyaWFibGUgbmFtZXMgaW4gdGhlIGxvbmctZm9ybSBkYXRhc2V0IChpLmUuLCBmb3IgZWFjaCB2YXJpYWJsZSwgaXQgc2hvdWxkIGluY2x1ZGUgYSBsaXN0IGVsZW1lbnQgbmFtZWQgd2l0aCB0aGUgdmFyaWFibGUgbmFtZSBhbmQgaW5jbHVkaW5nIGEgdmVjdG9yIG9mIHZhcmlhYmxlIG5hbWVzIHJlcG9ydGluZyB0aGUgbmFtZSBvZiBlYWNoIGl0ZW07IHdpdGggc2luZ2xlLWl0ZW0gbWVhc3VyZXMgb25seSB0aGUgdmFyaWFibGUgbmFtZSBzaG91bGQgYmUgc3BlY2lmaWVkLCB3aXRob3V0IGFueSB2ZWN0b3IpDQojJyBAcGFyYW0gd2lkZS52YXJpYWJsZXMgPSBsaXN0IG9mIHZhcmlhYmxlIG5hbWVzIGluIHRoZSB3aWRlLWZvcm0gZGF0YXNldCAoc2VlIGxvbmcudmFyaWFibGVzKQ0KIycgQHBhcmFtIHJlbW92ZS5maXJzdC5iZWVwID0gbG9naWNhbCB2YWx1ZSBkZXRlcm1pbmluZyB3aGV0aGVyIHRoZSBmaXJzdCBtZWFzdXJlbWVudCBvY2Nhc2lvbiB3aXRoaW4gZWFjaCBkYXkgc2hvdWxkIGJlIGV4Y2x1ZGVkIChUUlVFKSBvciBub3QgKEZBTFNFLCBkZWZhdWx0KQ0KIycgQHBhcmFtIHJlbW92ZS5maXJzdC5kYXkgPSBsb2dpY2FsIHZhbHVlIGRldGVybWluaW5nIHdoZXRoZXIgdGhlIGZpcnN0IGRheSBvZiBlYWNoIHBhcnRpY2lwYW50IHNob3VsZCBiZSBleGNsdWRlZCAoVFJVRSkgb3Igbm90IChGQUxTRSwgZGVmYXVsdCkNCiMnIEBwYXJhbSBsaXN0d2lzZS5kZWwgPSBsb2dpY2FsIHZhbHVlIGRldGVybWluaW5nIHdoZXRoZXIgYSBsaXN0LXdpc2UgZGVsZXRpb24gc2hvdWxkIGJlIGFwcGxpZWQgKFRSVUUpIG9yIG5vdCAoRkFMU0UsIGRlZmF1bHQpDQojJyBAcGFyYW0gY29tcGxpYW5jZS5jdXRvZmYgPSBudW1lcmljIHZhbHVlIGluZGV4aW5nIHRoZSBtaW5pbXVtIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgb3IgY29tcGxpYW5jZSByYXRlIGN1dC1vZmYgdXNlZCB0byBleGNsdWRlIHBhcnRpY2lwYW50cyAoTkEgYnkgZGVmYXVsdCwgbWVhbmluZyB0aGF0IGFsbCBwYXJ0aWNpcGFudHMgYXJlIGluY2x1ZGVkKQ0KIycgQHBhcmFtIGNvbXBsaWFuY2UudHlwZSA9IGNoYXJhY3RlciB2YWx1ZSBkZXRlcm1pbmluZyB3aGV0aGVyIHRoZSBjb21wbGlhbmNlLmN1dG9mZiB2YWx1ZSBpcyBleHByZXNzZWQgYXMgdGhlIG1pbmltdW0gbnVtYmVyIG9mIG9ic2VydmF0aW9ucyAoY29tcGxpYW5jZS50eXBlID0gIm9icyIpIG9yIGFzIHRoZSBtaW5pbXVtIGNvbXBsaWFuY2UgcmF0ZSAoY29tcGxpYW5jZS50eXBlPSJwZXJjIikNCiMnIEBwYXJhbSBtYXgubm9icyA9IGludGVnZXIgaW5kZXhpbmcgdGhlIG1heGltdW0gbnVtYmVyIG9mIHJlc3BvbnNlcyBwZXIgcGFydGljaXBhbnQgKHJlcXVpcmVkIHdoZW4gY29tcGxpYW5jZS50eXBlPSJwZXJjIikNCg0KaWxkLm1hbmlwIDwtIGZ1bmN0aW9uKGxvbmcsIHdpZGUsIGNsdXN0ZXIgPSAiSUQiLCBsb25nLnJlc3BUaW1lID0gIlJ1blRpbWVzdGFtcCIsDQogICAgICAgICAgICAgICAgICAgICAgcmVzcFRpbWUuZm9ybWF0ID0gIiVZLSVtLSVkICVIOiVNOiVTIiwNCiAgICAgICAgICAgICAgICAgICAgICBzY2hlZHVsZWRUaW1lcyA9IGxpc3QoYygiMDk6MTU6MDAiLCIwOTozMDowMCIsIjEwOjE1OjAwIiksICAjIGJlZXAgMQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCIxMDoyMDowMCIsIjEwOjMwOjAwIiwiMTA6NDA6MDAiKSwgICMgYmVlcCAyDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIjExOjUwOjAwIiwiMTI6MDA6MDAiLCIxMjoxMDowMCIpLCAgIyBiZWVwIDMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiMTM6MjA6MDAiLCIxMzozMDowMCIsIjEzOjQwOjAwIiksICAjIGJlZXAgNA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCIxNDo1MDowMCIsIjE1OjAwOjAwIiwiMTU6MTA6MDAiKSwgICMgYmVlcCA1DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIjE2OjIwOjAwIiwiMTY6MzA6MDAiLCIxNjo0MDowMCIpLCAgIyBiZWVwIDYNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiMTc6NTA6MDAiLCIxODowMDowMCIsIjE4OjEwOjAwIikpLCAjIGJlZXAgNw0KICAgICAgICAgICAgICAgICAgICAgIHNjaGVkdWxlZFRpbWVzLmZvcm1hdCA9ICIlSDolTTolUyIsDQogICAgICAgICAgICAgICAgICAgICAgbG9uZy52YXJpYWJsZXMgPSBsaXN0KE5WID0gYygidjEiLCJ2MiIsInYzIiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBURCA9IGMoImQxIiwiZDIiLCJkMyIsImQ0IiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUQyA9IGMoImMxIiwiYzIiLCJjMyIpKSwNCiAgICAgICAgICAgICAgICAgICAgICB3aWRlLnZhcmlhYmxlcyA9IGxpc3QoImdlbmRlciIsImFnZSIpLCANCiAgICAgICAgICAgICAgICAgICAgICByZW1vdmUuZmlyc3QuYmVlcCA9IEZBTFNFLCByZW1vdmUuZmlyc3QuZGF5ID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgbGlzdHdpc2UuZGVsID0gRkFMU0UsIGNvbXBsaWFuY2UuY3V0b2ZmID0gTkEsIA0KICAgICAgICAgICAgICAgICAgICAgIGNvbXBsaWFuY2UudHlwZSA9IGMoIm9icyIsInBlcmMiKSwgbWF4Lm5vYnMgPSAxOCl7DQogIA0KICAjIHJlbmFtaW5nIHZhcmlhYmxlcw0KICBjb2xuYW1lcyhsb25nKVt3aGljaChjb2xuYW1lcyhsb25nKT09Y2x1c3RlcildIDwtICJJRCIgIyBjbHVzdGVyIHZhcmlhYmxlIGluIHRoZSBsb25nIGRhdGFzZXQNCiAgY29sbmFtZXMod2lkZSlbd2hpY2goY29sbmFtZXMod2lkZSk9PWNsdXN0ZXIpXSA8LSAiSUQiICMgY2x1c3RlciB2YXJpYWJsZSBpbiB0aGUgd2lkZSBkYXRhc2V0DQogIGNvbG5hbWVzKGxvbmcpW3doaWNoKGNvbG5hbWVzKGxvbmcpPT1sb25nLnJlc3BUaW1lKV0gPC0gInJlc3BUaW1lIiAjIHRpbWUgdmFyaWFibGUgaW4gdGhlIGxvbmcgZGF0YXNldA0KICANCiAgIyAxKSBkYXRhIHJlYWRpbmcgKHJlbW92aW5nIHVudXNlZnVsIGNvbHVtbnMpLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uDQogICMuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLg0KICBsb25nIDwtIGxvbmdbLHdoaWNoKGNvbG5hbWVzKGxvbmcpICVpbiUgYygiSUQiLCJyZXNwVGltZSIsYXMuY2hhcmFjdGVyKHVubGlzdChsb25nLnZhcmlhYmxlcykpKSldDQogIHdpZGUgPC0gd2lkZVssd2hpY2goY29sbmFtZXMod2lkZSkgJWluJSBjKCJJRCIsYXMuY2hhcmFjdGVyKHVubGlzdCh3aWRlLnZhcmlhYmxlcykpKSldDQogIA0KICAjIHByaW50IGluZm8NCiAgY2F0KCJEYXRhIHByZS1wcm9jZXNzaW5nLi4uXG5cbiIpDQogIA0KICAjIDIpIHRlbXBvcmFsIHN5bmNocm9uaXphdGlvbi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uDQogICMuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4NCiAgbG9uZyR0aW1lIDwtIGFzLlBPU0lYY3Qoc3RyZnRpbWUoYXMuUE9TSVhjdChsb25nJHJlc3BUaW1lLCBmb3JtYXQ9IiVZLSVtLSVkICVIOiVNOiVTIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1hdD0iJUg6JU06JVMiKSxmb3JtYXQ9IiVIOiVNOiVTIikgIyByZXNwIHRpbWUNCiAgbG9uZyRkYXRlIDwtIGFzLkRhdGUoc3Vic3RyKGxvbmckcmVzcFRpbWUsMSwxMCksZm9ybWF0PSIlWS0lbS0lZCIpICMgcmVzcCBkYXRlIHdpdGhvdXQgdGltZQ0KICAjIGNyZWF0aW5nICdkYXknIHZhcmlhYmxlIGJhc2Ugb24gcmVzcG9uc2UgZGF0ZXMNCiAgbG9uZyRkYXkgPC0gMSANCiAgZm9yKGkgaW4gMjpucm93KGxvbmcpKXsgaWYobG9uZ1tpLCJJRCJdICE9IGxvbmdbaS0xLCJJRCJdKXsgbG9uZ1tpLCJkYXkiXSA8LSAxIH0gZWxzZSB7DQogICAgICBpZighaXMubmEobG9uZ1tpLCJkYXRlIl0pICYgIWlzLm5hKGxvbmdbaS0xLCJkYXRlIl0pICYgDQogICAgICAgICBhcy5QT1NJWGx0KGxvbmdbaSwiZGF0ZSJdKSR3ZGF5ICE9IGFzLlBPU0lYbHQobG9uZ1tpLTEsImRhdGUiXSkkd2RheSl7DQogICAgICAgIGxvbmdbaSwiZGF5Il0gPC0gbG9uZ1tpLTEsImRheSJdICsgMSB9IGVsc2V7IGxvbmdbaSwiZGF5Il0gPC0gbG9uZ1tpLTEsImRheSJdIH19fQ0KICAjIGNyZWF0aW5nICdiZWVwJyB2YXJpYWJsZSBiYXNlZCBvbiBzY2hlZHVsZWQgdGltZXN0YW1wcw0KICBpZighaXMubmEoc2NoZWR1bGVkVGltZXNbWzFdXVsxXSkpeyBjZW50cmFsLnRpbWVzIDwtIGMoKSAjIHNhdmluZyB2ZWN0b3Igb2YgY2VudHJhbCB0aW1lcw0KICAgIGZvcihpIGluIDE6bGVuZ3RoKHNjaGVkdWxlZFRpbWVzKSl7ICMgYXNzaWduIGJlZXAgdmFsdWUgZGVwZW5kaW5nIG9uIGVhY2ggY291cGxlIG9mIG1pbi1tYXgNCiAgICAgIGxvbmdbIWlzLm5hKGxvbmckdGltZSkgJiANCiAgICAgICAgICAgICBsb25nJHRpbWUgPiAoYXMuUE9TSVhjdChzY2hlZHVsZWRUaW1lc1tbaV1dWzFdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JtYXQgPSBzY2hlZHVsZWRUaW1lcy5mb3JtYXQpIC0gMTAqNjApICYgDQogICAgICAgICAgICBsb25nJHRpbWUgPCAoYXMuUE9TSVhjdChzY2hlZHVsZWRUaW1lc1tbaV1dWzNdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1hdCA9IHNjaGVkdWxlZFRpbWVzLmZvcm1hdCkgKyAxMCo2MCksImJlZXAiXSA8LSBpIA0KICAgICAgY2VudHJhbC50aW1lcyA8LSBjKGNlbnRyYWwudGltZXMsIHNjaGVkdWxlZFRpbWVzW1tpXV1bMl0pIH0NCiAgIyB3aGVuIHRpbWUgaXMgb3V0c2lkZSB0aGUgc2NoZWR1bGVkIGludGVydmFsLCB0aGUgY2xvc2VzdCAnYmVlcCcgaXMgYXNzaWduZWQNCiAgZm9yKGkgaW4gMTpucm93KGxvbmcpKXsgcmVxdWlyZShiaXJrKSANCiAgICBpZihpcy5uYShsb25nW2ksImJlZXAiXSkgJiAhaXMubmEobG9uZ1tpLCJ0aW1lIl0pKXsgDQogICAgICBsb25nW2ksImJlZXAiXSA8LSB3aGljaC5jbG9zZXN0KGFzLlBPU0lYY3QoY2VudHJhbC50aW1lcywgZm9ybWF0ID0gc2NoZWR1bGVkVGltZXMuZm9ybWF0KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9uZ1tpLCJ0aW1lIl0pIH19fQ0KICANCiAgIyAzKSBkYXRhIGNsZWFuaW5nLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLg0KICAjLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uDQogIG4xLmxvbmc8LW5yb3cobG9uZykgIyBzYXZlIE4ub2JzIGZvciBjb21wYXJpc29uDQogIG4yLmxvbmc8LWxlbmd0aCh0YWJsZShsb25nJElEKSkNCiAgbjIud2lkZTwtbGVuZ3RoKHRhYmxlKHdpZGUkSUQpKQ0KICBuIDwtIDE7IGZvcihpIGluIDE6bGVuZ3RoKHdpZGUudmFyaWFibGVzKSl7IGlmKGxlbmd0aCh3aWRlLnZhcmlhYmxlc1tpXSkgPiAxKXsgbiA8LSBuICsgMSB9fQ0KICAjIDMuMSkgcmVtb3ZpbmcgbWlzc2luZyByZXNwcyBmcm9tIHRoZSB3aWRlLWZvcm0gZGF0YXNldC4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uDQogIGlmKG4gPT0gMSl7IHdpZGUgPC0gbmEub21pdCh3aWRlWyxjKCJJRCIsdW5saXN0KHdpZGUudmFyaWFibGVzKSldKSANCiAgfSBlbHNlIHsgVmFyTmFtZXMgPC0gIklEIg0KICAgIGZvcihpIGluIDE6bGVuZ3RoKHdpZGUudmFyaWFibGVzKSl7IFZhck5hbWVzIDwtIGMoVmFyTmFtZXMsbmFtZXMod2lkZS52YXJpYWJsZXNbaV0pKSB9DQogICAgd2lkZSA8LSBuYS5vbWl0KHdpZGVbLFZhck5hbWVzXSkgfQ0KICBsb25nIDwtIGxvbmdbbG9uZyRJRCAlaW4lIGFzLmNoYXJhY3Rlcih3aWRlJElEKSxdICMgcmVtb3ZpbmcgY2FzZXMgdGhhdCBhcmUgbm90IGluY2x1ZGVkIGluIHRoZSB3aWRlIGRhdGFzZXQNCiAgbG9uZyRJRCA8LSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKGxvbmckSUQpKSAjIHJlc2V0dGluZyBsZXZlbHMNCiAgY2F0KCJEYXRhIGNsZWFuaW5nOlxuLSIsbjEubG9uZy1ucm93KGxvbmcpLCJvYnMsIixuMi5sb25nLW5sZXZlbHMobG9uZyRJRCksDQogICAgICAicGFydGljaXBhbnRzIG5vdCBpbiB0aGUgd2lkZSBkYXRhc2V0IikNCiAgIyAzLjIpIHJlbW92aW5nIGNhc2VzIHdpdGggbWlzc2luZyByZXNwb25zZXMgdG8gdGhlIGxvbmctZm9ybSBkYXRhc2V0Li4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLg0KICBsb25nIDwtIGxvbmdbIWlzLm5hKGxvbmckcmVzcFRpbWUpLF0gDQogIGxvbmckSUQgPC0gYXMuZmFjdG9yKGFzLmNoYXJhY3Rlcihsb25nJElEKSkgIyByZXNldHRpbmcgbGV2ZWxzDQogIHdpZGUgPC0gd2lkZVt3aWRlJElEICVpbiUgbGV2ZWxzKGxvbmckSUQpLF0gIyByZW1vdmluZyBjYXNlcyB0aGF0IGFyZSBub3QgaW5jbHVkZWQgaW4gdGhlIGxvbmcgZGF0YXNldA0KICB3aWRlJElEIDwtIGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIod2lkZSRJRCkpICMgcmVzZXR0aW5nIGxldmVscw0KICBjYXQoIlxuLSIsbjIud2lkZS1ucm93KHdpZGUpLCJwYXJ0aWNpcGFudHMgbm90IGluIHRoZSBsb25nIGRhdGFzZXQiKQ0KICAjIDMuMykgcmVtb3ZpbmcgZmlyc3Qgb2JzZXJ2YXRpb24gd2l0aGluIGVhY2ggZGF5Li4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uDQogIG4xLmxvbmc8LW5yb3cobG9uZyk7IG4yLmxvbmc8LW5sZXZlbHMobG9uZyRJRCkgIyBzYXZpbmcgc2FtcGxlIHNpemVzIGZvciBjb21wYXJpc29uDQogIGlmKGlzVFJVRShyZW1vdmUuZmlyc3QuYmVlcCkpeyANCiAgICBpZighaXMubmEoc2NoZWR1bGVkVGltZXNbWzFdXVsxXSkpeyANCiAgICAgIGxvbmcgPC0gbG9uZ1tsb25nJGJlZXAhPTEsXSAjIHJlbW92aW5nIDFzdCAnYmVlcCcgd2hlbiBzY2hlZHVsZWRUaW1lcyBhcmUgc3BlY2lmaWVkDQogICAgfSBlbHNlIHsgTE9ORyA8LSBsb25nWzAsXSAjIHJlbW92aW5nIHRoZSBmaXJzdCBkYWlseSBvYnNlcnZhdGlvbiB3aGVuIHNjaGVkdWxlZFRpbWVzIGFyZSBOT1Qgc3BlY2lmaWVkDQogICAgICBsb25nJElEZGF5IDwtIHBhc3RlKGxvbmckSUQsbG9uZyRkYXkpICMgY3JlYXRpbmcgaWRlbnRpZmllciBiYXNlZCBvbiBib3RoIElEIGFuZCBkYXkNCiAgICAgIGZvcihvYnMgaW4gbGV2ZWxzKGFzLmZhY3Rvcihsb25nJElEZGF5KSkpeyBMT05HIDwtIHJiaW5kKExPTkcsbG9uZ1tsb25nJElEZGF5ID09IG9icyxdWy0xLF0pIH0NCiAgICAgIGxvbmcgPC0gTE9ORyB9fQ0KICAjIDMuNCkgcmVtb3ZpbmcgZmlyc3QgZGF5Li4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uDQogIGlmKGlzVFJVRShyZW1vdmUuZmlyc3QuZGF5KSl7IGxvbmcgPC0gbG9uZ1tsb25nJGRheSE9MSxdIH0gDQogIGxvbmckSUQgPC0gYXMuZmFjdG9yKGFzLmNoYXJhY3Rlcihsb25nJElEKSkgIyByZXNldHRpbmcgbGV2ZWxzDQogIGlmKGlzVFJVRShyZW1vdmUuZmlyc3QuYmVlcCkgfCBpc1RSVUUocmVtb3ZlLmZpcnN0LmRheSkpew0KICAgIGNhdCgiXG4tIixuMS5sb25nLW5yb3cobG9uZyksIm9icywiLG4yLmxvbmctbmxldmVscyhsb25nJElEKSwNCiAgICAgICAgInBhcnRpY2lwYW50cyBmb2xsb3dpbmcgdGhlIHJlbW92YWwgb2YgdGhlIDFzdCIsDQogICAgICAgIGlmZWxzZShpc1RSVUUocmVtb3ZlLmZpcnN0LmJlZXApICYgaXNUUlVFKHJlbW92ZS5maXJzdC5kYXkpLCJkYXkgYW5kIHRoZSAxc3QgZGFpbHkgc3VydmV5IiwNCiAgICAgICAgICAgICAgIGlmZWxzZShpc1RSVUUocmVtb3ZlLmZpcnN0LmJlZXApLCJkYWlseSBzdXJ2ZXkiLCJkYXkiKSkpIH0NCiAgIyAzLjUpIGxpc3Qtd2lzZSBkZWxldGlvbi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLg0KICBuMS5sb25nPC1ucm93KGxvbmcpOyBuMi5sb25nPC1ubGV2ZWxzKGxvbmckSUQpICMgc2F2aW5nIHNhbXBsZSBzaXplcyBmb3IgY29tcGFyaXNvbg0KICBpZihpc1RSVUUobGlzdHdpc2UuZGVsKSl7IGxvbmcgPC0gbmEub21pdChsb25nWyxjKCJJRCIsInJlc3BUaW1lIiwiZGF5Iixhcy5jaGFyYWN0ZXIodW5saXN0KGxvbmcudmFyaWFibGVzKSkpXSkgDQogICAgbG9uZyRJRCA8LSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKGxvbmckSUQpKSAjIHJlc2V0dGluZyBsZXZlbHMNCiAgICBjYXQoIlxuLSIsbjEubG9uZy1ucm93KGxvbmcpLCJvYnMsIixuMi5sb25nLW5sZXZlbHMobG9uZyRJRCksDQogICAgICAgICJwYXJ0aWNpcGFudHMgZm9sbG93aW5nIGxpc3Qtd2lzZSBkZWxldGlvbiIpfQ0KICAjIDMuNSkgZXhjbHVkaW5nIHBhcnRpY2lwYW50cyBiYXNlZCBvbiBjb21wbGlhbmNlIHJhdGUuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uDQogIGlmKCFpcy5uYShjb21wbGlhbmNlLmN1dG9mZikpeyBuMS5sb25nPC1ucm93KGxvbmcpOyBuMi5sb25nPC1ubGV2ZWxzKGlsZCRJRCkgIyBzYXZpbmcgc2FtcGxlIHNpemVzDQogICAgaWYoY29tcGxpYW5jZS50eXBlPT0ib2JzIil7ICMgY29tcGxpYW5jZSBiYXNlZCBvbiBvdmVyYWxsIG51bWJlciBvZiBvYnNlcnZhdGlvbnMNCiAgICAgIGZvcihkYXkgaW4gbWluKGFzLmludGVnZXIobG9uZyRkYXkpKTptYXgoYXMuaW50ZWdlcihsb25nJGRheSkpKXsgDQogICAgICAgIGZvcihpIGluIDE6bnJvdyh3aWRlKSl7ICMgY29tcHV0aW5nIG5vLiBvYnMgcGVyIGRheSBhbmQgcGFydGljaXBhbnQNCiAgICAgICAgICB3aWRlW2kscGFzdGUwKCJuLmRheSIsZGF5KV0gPC0gbnJvdyhsb25nW2xvbmckSUQ9PWFzLmNoYXJhY3Rlcih3aWRlW2ksIklEIl0pICYgbG9uZyRkYXk9PWRheSxdKSB9DQogICAgICAgIGNvbG5hbWVzKHdpZGUpW25jb2wod2lkZSldIDwtICJuRGF5IiAjIHJlbmFtaW5nIGNvbHVtbg0KICAgICAgICB3aWRlIDwtIHdpZGVbd2lkZSRuRGF5ID49IGNvbXBsaWFuY2UuY3V0b2ZmLF0gIyByZW1vdmluZyBwYXJ0aWNpcGFudHMNCiAgICAgICAgY29sbmFtZXMod2lkZSlbbmNvbCh3aWRlKV0gPC0gcGFzdGUwKCJuLmRheSIsZGF5KSB9DQogICAgfSBlbHNlIGlmKGNvbXBsaWFuY2UudHlwZT09InBlcmMiKXsgIyBjb21wbGlhbmNlIGJhc2VkIG9uIHBlcmNlbnRhZ2Ugb2YgcmVzcG9uc2VzDQogICAgICAgIGZvcihpIGluIDE6bnJvdyh3aWRlKSl7IA0KICAgICAgICAgIHdpZGVbaSwiY29tcFJhdGUiXSA8LSAxMDAqbnJvdyhsb25nW2xvbmckSUQ9PWFzLmNoYXJhY3Rlcih3aWRlW2ksIklEIl0pLF0pL21heC5ub2JzIH0NCiAgICAgIHdpZGUgPC0gd2lkZVt3aWRlJGNvbXBSYXRlID49IGNvbXBsaWFuY2UuY3V0b2ZmLF0gfQ0KICAgIGxvbmcgPC0gbG9uZ1tsb25nJElEICVpbiUgYXMuY2hhcmFjdGVyKHdpZGUkSUQpLF0gIyByZW1vdmluZyB0aGUgc2FtZSBwYXJ0aWNpcGFudHMgZnJvbSB0aGUgbG9uZyBkYXRhc2V0DQogICAgbG9uZyRJRCA8LSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKGxvbmckSUQpKSAjIHJlc2V0dGluZyBsZXZlbHMNCiAgICBjYXQoIlxuLSIsbjEubG9uZy1ucm93KGxvbmcpLCJvYnMsIixuMi5sb25nLW5sZXZlbHMobG9uZyRJRCksDQogICAgICAicGFydGljaXBhbnRzIHdpdGgiLGlmZWxzZShjb21wbGlhbmNlLnR5cGU9PSJvYnMiLHBhc3RlKCJsZXNzIHRoYW4iLGNvbXBsaWFuY2UuY3V0b2ZmLCJvYnMgcGVyIGRheSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoImNvbXBsaWFuY2UgcmF0ZSA8Iixjb21wbGlhbmNlLmN1dG9mZiwiJSIpKSkgfQ0KICANCiAgIyA0KSBkYXRhIG1lcmdpbmcuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uDQogICMuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLg0KICByZXF1aXJlKHBseXIpDQogIGxvbmcgPC0gam9pbihsb25nLCB3aWRlLCBieSA9ICJJRCIpDQogIA0KICAjIDUpIGNvbXB1dGluZyBjb21wb3NpdGUgc2NvcmVzLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4NCiAgIy4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uDQogIG4gPC0gMTsgZm9yKGkgaW4gMTpsZW5ndGgobG9uZy52YXJpYWJsZXMpKXsgaWYobGVuZ3RoKGxvbmcudmFyaWFibGVzW1tpXV0pID4gMSl7IG4gPC0gbiArIDEgfX0NCiAgaWYobiA+IDEpew0KICAgIGZvcihpIGluIDE6bGVuZ3RoKGxvbmcudmFyaWFibGVzKSl7DQogICAgICBsb25nWyxuYW1lcyhsb25nLnZhcmlhYmxlcylbaV1dIDwtIGFwcGx5KGxvbmdbLGxvbmcudmFyaWFibGVzW1tpXV1dLDEsbWVhbixuYS5ybT1UUlVFKSB9fQ0KICANCiAgIyA2KSBkYXRhIGNlbnRlcmluZy4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uDQogICMuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLg0KICBpZihuID4gMSl7DQogICAgZm9yKFZhck5hbWUgaW4gbmFtZXMobG9uZy52YXJpYWJsZXMpKXsgDQogICAgICBjb2xuYW1lcyhsb25nKVtjb2xuYW1lcyhsb25nKT09VmFyTmFtZV0gPC0gIlZhck5hbWUiICMgY2hhbmdpbmcgdmFyaWFibGUgbmFtZQ0KICAgICAgY2x1c3QubWVhbnMgPC0gYWdncmVnYXRlKHggPSBsb25nJFZhck5hbWUsICMgY2x1c3RlciBtZWFucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gbGlzdChsb25nJElEKSwgRlVOID0gbWVhbiwgbmEucm0gPSBUUlVFKSANCiAgICAgIGNvbG5hbWVzKGNsdXN0Lm1lYW5zKSA8LSBjKCJJRCIsIlZhck5hbWViIikgIyByZW5hbWluZyB2YXJpYWJsZQ0KICAgICAgbG9uZyA8LSBqb2luKGxvbmcsIGNsdXN0Lm1lYW5zLCBieT0iSUQiKSAjIGpvaW5pbmcgY2x1c3RlciBtZWFuIHRvIGxvbmctZm9ybSBkYXRhc2V0DQogICAgICBsb25nJFZhck5hbWV3IDwtIGxvbmckVmFyTmFtZSAtIGxvbmckVmFyTmFtZWIgIyBjbHVzdGVyIG1lYW4gY2VudGVyaW5nDQogICAgICBjb2xuYW1lcyhsb25nKSA8LSBnc3ViKCJWYXJOYW1lIixWYXJOYW1lLGNvbG5hbWVzKGxvbmcpKSB9fSAjIGJhY2sgdG8gdGhlIG9yaWdpbmFsIHZhcmlhYmxlIG5hbWUNCiAgDQogICMgcHJpbnQgaW5mbw0KICBsb25nJElEIDwtIGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIobG9uZyRJRCkpDQogIGNhdCgiXG5cblRvdGFsIG51bWJlciBvZiByZXRhaW5lZCBvYnNlcnZhdGlvbnMgPSIsbnJvdyhsb25nKSwiZnJvbSIsbmxldmVscyhsb25nJElEKSwicGFydGljaXBhbnRzIikNCiAgDQogICMgcmV0dXJuaW5nIGRhdGENCiAgcmV0dXJuKGxvbmcpIH0NCmBgYA0KPC9wPg0KPC9kZXRhaWxzPg0KDQo8YnI+DQoNCiMjIDMuMS4gTXVsdGl2ZXJzZSBvZiBkYXRhc2V0cw0KDQpGaXJzdCwgd2UgYXBwbHkgdGhlIGZ1bmN0aW9uIHRvIHRoZSByYXcgZGF0YXNldHMgYnkgY29uc2lkZXJpbmcgYWx0ZXJuYXRpdmUgZGF0YSBtYW5pcHVsYXRpb24gc2NlbmFyaW9zLg0KYGBge3IgfQ0KIyByZWFkaW5nIHJhdyBkYXRhc2V0cw0KbG9uZyA8LSByZWFkLmNzdigiUzVfcHJvY2Vzc2VkRGF0YS9FU01fcHJvY2Vzc2VkLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBUUlVFKSAjIElMRCBkYXRhc2V0DQp3aWRlIDwtIHJlYWQuY3N2KCJTNV9wcm9jZXNzZWREYXRhL1JFVFJPX3Byb2Nlc3NlZC5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gVFJVRSkgIyBwcmVsaW1pbmFyeSBxdWVzdGlvbm5haXJlDQoNCiMgc2NlbmFyaW8gIzE6IHNhbWUgc2V0dGluZ3MgYXMgYWJvdmUgKGEgcGFydCBmcm9tIHRoZSBzaW5nbGUgY2FyZWxlc3MgcmVzcG9uc2UsIHdoaWNoIGlzIHJldGFpbmVkKQ0KbTEgPC0gaWxkLm1hbmlwKGxvbmcsIHdpZGUsIA0KICAgICAgICAgICAgICAgIHJlbW92ZS5maXJzdC5iZWVwID0gVFJVRSwgIGxpc3R3aXNlLmRlbCA9IFRSVUUsIA0KICAgICAgICAgICAgICAgIGNvbXBsaWFuY2UuY3V0b2ZmID0gMiwgY29tcGxpYW5jZS50eXBlID0gIm9icyIpDQojIHNjZW5hcmlvICMyOiBubyBkYXRhIGNsZWFuaW5nIChpLmUuLCByZXRhaW5pbmcgYWxsIGF2YWlsYWJsZSBvYnNlcnZhdGlvbnMpDQptMiA8LSBpbGQubWFuaXAobG9uZywgd2lkZSkNCiMgc2NlbmFyaW8gIzM6IHJlbW92aW5nIGZpcnN0IHJlc3BvbnNlIHJlZ2FyZGxlc3Mgb2YgcmVzcG9uc2UgdGltZQ0KbTMgPC0gaWxkLm1hbmlwKGxvbmcsIHdpZGUsIA0KICAgICAgICAgICAgICAgIHJlbW92ZS5maXJzdC5iZWVwID0gVFJVRSwgIGxpc3R3aXNlLmRlbCA9IFRSVUUsIA0KICAgICAgICAgICAgICAgIGNvbXBsaWFuY2UuY3V0b2ZmID0gMiwgY29tcGxpYW5jZS50eXBlID0gIm9icyIsDQogICAgICAgICAgICAgICAgc2NoZWR1bGVkVGltZXMgPSBOQSkNCiMgc2NlbmFyaW8gIzQ6IHJlbW92aW5nIGZpcnN0IGRheQ0KbTQgPC0gaWxkLm1hbmlwKGxvbmcsIHdpZGUsIA0KICAgICAgICAgICAgICAgIHJlbW92ZS5maXJzdC5kYXkgPSBUUlVFLCAgIGxpc3R3aXNlLmRlbCA9IFRSVUUsIA0KICAgICAgICAgICAgICAgIGNvbXBsaWFuY2UuY3V0b2ZmID0gMiwgY29tcGxpYW5jZS50eXBlID0gIm9icyIpDQojIHNjZW5hcmlvICM1OiBzdHJpY3RlciBjb21wbGlhbmNlIHJhdGUgKDMrIG9ic2VydmF0aW9ucyBwZXIgZGF5KQ0KbTUgPC0gaWxkLm1hbmlwKGxvbmcsIHdpZGUsIA0KICAgICAgICAgICAgICAgIHJlbW92ZS5maXJzdC5iZWVwID0gVFJVRSwgbGlzdHdpc2UuZGVsID0gVFJVRSwgDQogICAgICAgICAgICAgICAgY29tcGxpYW5jZS5jdXRvZmYgPSAzLCBjb21wbGlhbmNlLnR5cGUgPSAib2JzIikNCiMgc2NlbmFyaW8gIzY6IGNvbXBsaWFuY2UgcmF0ZSA+IDMwJQ0KbTYgPC0gaWxkLm1hbmlwKGxvbmcsIHdpZGUsIA0KICAgICAgICAgICAgICAgIHJlbW92ZS5maXJzdC5iZWVwID0gVFJVRSwgbGlzdHdpc2UuZGVsID0gVFJVRSwgDQogICAgICAgICAgICAgICAgY29tcGxpYW5jZS5jdXRvZmYgPSAzMCwgY29tcGxpYW5jZS50eXBlID0gInBlcmMiKQ0KIyBzY2VuYXJpbyAjNzogY29tcGxpYW5jZSByYXRlID4gNzUlDQptNyA8LSBpbGQubWFuaXAobG9uZywgd2lkZSwgDQogICAgICAgICAgICAgICAgcmVtb3ZlLmZpcnN0LmJlZXAgPSBUUlVFLCBsaXN0d2lzZS5kZWwgPSBUUlVFLCANCiAgICAgICAgICAgICAgICBjb21wbGlhbmNlLmN1dG9mZiA9IDc1LCBjb21wbGlhbmNlLnR5cGUgPSAicGVyYyIpDQojIHNjZW5hcmlvICM4OiAoNCkgYW5kICg3KQ0KbTggPC0gaWxkLm1hbmlwKGxvbmcsIHdpZGUsIA0KICAgICAgICAgICAgICAgIHJlbW92ZS5maXJzdC5iZWVwID0gVFJVRSwgbGlzdHdpc2UuZGVsID0gVFJVRSwgDQogICAgICAgICAgICAgICAgY29tcGxpYW5jZS5jdXRvZmYgPSAzMCwgY29tcGxpYW5jZS50eXBlID0gInBlcmMiLA0KICAgICAgICAgICAgICAgIHNjaGVkdWxlZFRpbWVzID0gTkEpDQojIHNjZW5hcmlvICM5OiAoNCkgYW5kICg4KQ0KbTkgPC0gaWxkLm1hbmlwKGxvbmcsd2lkZSwgDQogICAgICAgICAgICAgICAgIHJlbW92ZS5maXJzdC5iZWVwID0gVFJVRSwgbGlzdHdpc2UuZGVsID0gVFJVRSwgDQogICAgICAgICAgICAgICAgIGNvbXBsaWFuY2UuY3V0b2ZmID0gNzUsIGNvbXBsaWFuY2UudHlwZSA9ICJwZXJjIiwNCiAgICAgICAgICAgICAgICBzY2hlZHVsZWRUaW1lcyA9IE5BKQ0KYGBgDQoNCjxicj4NCg0KIyMgMy4yLiBSZXN1bHRzDQoNCkhlcmUsIHdlIGZpdCB0aGUgc2FtZSBtb2RlbHMgZml0dGVkIGFib3ZlIG9uIGVhY2ggZ2VuZXJhdGVkIGRhdGFzZXQsIGFuZCB3ZSBzdW1tYXJpemUgdGhlIHJlc3VsdHMgYnkgcmVwb3J0aW5nIHRoZSB2YWx1ZSBgVFJVRWAgKGkuZS4sIHNpZ25pZmljYW50KSBvciBgRkFMU0VgIChpLmUuLCBub24tc2lnbmlmaWNhbnQpIGZvciBlYWNoIG1haW4gYW5kIGludGVyYWN0aXZlIGVmZmVjdCBvZiBpbnRlcmVzdC4gV2UgY2FuIHNlZSB0aGF0IHRoZSByZXN1bHRzIG9idGFpbmVkIGFib3ZlIGFyZSBxdWl0ZSByb2J1c3QgYWNyb3NzIHRoZSBjb25zaWRlcmVkIHNjZW5hcmlvcy4gU3BlY2lmaWNhbGx5LCB0aGUgbW9zdCByb2J1c3QgZmluZGluZ3MgY29uY2VybiB0aGUgbmVnYXRpdmUgbGV2ZWwtMSBlZmZlY3Qgb2YgdGFzayBjb250cm9sIChzaWduaWZpY2FudCBhY3Jvc3MgYWxsIHNjZW5hcmlvcykgYW5kIHRoZSBsYWNrIG9mIGxldmVsLTEgaW50ZXJhY3Rpb24gKG5vbi1zaWduaWZpY2FudCBhY3Jvc3MgYWxsIHNjZW5hcmlvcykuIFRoZSBtYWluIGVmZmVjdCBvZiB0YXNrIGRlbWFuZHMgZXN0aW1hdGVkIGJ5IE1vZGVsIDEgaXMgYWxzbyBxdWl0ZSByb2J1c3QsIGJlaW5nIG5vbi1zaWduaWZpY2FudCBvbmx5IGluIG9uZSBjYXNlIChpLmUuLCByZW1vdmFsIG9mIHRoZSBmaXJzdCBkYXkpLiBGaW5hbGx5LCB0aGUgbWFpbiBhbmQgaW50ZXJhY3RpdmUgZWZmZWN0cyBlc3RpbWF0ZWQgYnkgTW9kZWwgMiBiZWNvbWUgbm9uLXNpZ25pZmljYW50IG9ubHkgd2hlbiBhIGNvbXBsaWFuY2UgcmF0ZSBvZiA3MCUgaXMgYXBwbGllZCwgeWV0IHRoZSByZXN1bHRpbmcgZGF0YXNldHMgYXJlIHZlcnkgc21hbGwgKGkuZS4sICpuMSogcmFuZ2luZyBmcm9tIDIxNiB0byAzNTgsICpuMiogcmFuZ2luZyBmcm9tIDE0IHRvIDIzKS4gT3ZlcmFsbCwgc3VjaCByb2J1c3RuZXNzIGNoZWNrcyAqKnN1cHBvcnQgdGhlIGdlbmVyYWxpemFiaWxpdHkgb2Ygb3VyIGZpbmRpbmdzKiouDQpgYGB7ciB9DQojIG11bHRpdmVyc2Ugb2YgZGF0YXNldHMgYXMgYSBsaXN0DQptIDwtIGxpc3QobTEsbTIsbTMsbTQsbTUsbTYsbTcsbTgsbTkpDQoNCiMgZGF0YS5mcmFtZSBvZiByZXN1bHRzIHRvIGJlIGZpbGxlZA0Kb3V0IDwtIGRhdGEuZnJhbWUobWF0cml4KG5yb3c9MCxuY29sPTgpKQ0KY29sbmFtZXMob3V0KSA8LSBjKCJOMSIsIk4yIiwibTEuVER3IiwibTEuVEN3IiwibTEuaW50IiwibTIuVER3IiwibTIuVENiIiwibTIuaW50IikNCg0KIyBmaXR0aW5nIG1vZGVscyBvbiBlYWNoIGRhdGFzZXQNCmZvcihpIGluIDE6bGVuZ3RoKG0pKXsNCiAgZml0MSA8LSBsbWVyKE5WIH4gVER3ICogVEN3ICsgYWdlICsgZ2VuZGVyICsgKFREd3xJRCksIGRhdGEgPSBtW1tpXV0pDQogIGZpdDIgPC0gbG1lcihOViB+IFREdyAqIFRDYiArIGFnZSArIGdlbmRlciArIChURHd8SUQpLCBkYXRhID0gbVtbaV1dKQ0KICBvdXQgPC0gcmJpbmQob3V0LCAjIGV4dHJhY3RpbmcgcmVzdWx0cyAoaS5lLiwgZWZmZWN0cyBtYXJrZWQgYXMgVFJVRSBpZiBDb2VmZi4vU0UgPiAxLjk2LCBGQUxTRSBvdGhlcndpc2UpDQogICAgICAgICAgICAgICBkYXRhLmZyYW1lKE4xID0gbGVuZ3RoKHJlc2lkdWFscyhmaXQxKSksIE4yID0gYXMuaW50ZWdlcihzdW1tYXJ5KGZpdDEpJG5ncnBzKSwgIyBzYW1wbGUgc2l6ZXMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbTEuVER3PWFicyhzdW1tYXJ5KGZpdDEpJGNvZWZmaWNpZW50c1syLDNdKT4xLjk2LCAjIG1vZGVsIDEgbWFpbiBlZmZlY3RzDQogICAgICAgICAgICAgICAgICAgICAgICAgIG0xLlRDdz1hYnMoc3VtbWFyeShmaXQxKSRjb2VmZmljaWVudHNbMywzXSk+MS45NiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIG0xLmludD1hYnMoc3VtbWFyeShmaXQxKSRjb2VmZmljaWVudHNbNiwzXSk+MS45NiwgIyBtb2RlbCAxIGludGVyYWN0aW9uDQogICAgICAgICAgICAgICAgICAgICAgICAgIG0yLlREdz1hYnMoc3VtbWFyeShmaXQyKSRjb2VmZmljaWVudHNbMiwzXSk+MS45NiwgIyBtb2RlbCAyIG1haW4gZWZmZWN0cw0KICAgICAgICAgICAgICAgICAgICAgICAgICBtMi5UQ2I9YWJzKHN1bW1hcnkoZml0MikkY29lZmZpY2llbnRzWzMsM10pPjEuOTYsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBtMi5pbnQ9YWJzKHN1bW1hcnkoZml0MikkY29lZmZpY2llbnRzWzYsM10pPjEuOTYpKSB9ICMgbW9kZWwgMiBpbnRlcmFjdGlvbg0KY2JpbmQoZGF0YT1jKCIxLiBPcmlnaW5hbCIsIjIuIEFsbCBpbiIsIjMuIDFzdCByZXNwIG91dCIsIjQuIDFzdCBkYXkgb3V0IiwgIyBwcmludGluZyByZXN1bHRzDQogICAgICAgICAgICAgIjUuIDMrIG9icy9kYXkiLCI2LiAzMCUgY29tcGwiLCI3LiA3MCUgY29tcGwiLCI4LiAoNCkgJiAoNykiLCIxOS4gKDQpICYgKDgpIiksb3V0KSAjIG5hbWluZyBzY2VuYXJpb3MNCmBgYA0KDQo8YnI+DQoNCiMgUmVmZXJlbmNlcyB7I3JlZn0NCg0KLSBDYXVnaGxpbiwgRC4gRS4gKDIwMjMpLiAqUiBmb3IgSFI6IEFuIEludHJvZHVjdGlvbiB0byBIdW1hbiBSZXNvdXJjZSBBbmFseXRpY3MgVXNpbmcgUiouIGh0dHBzOi8vcmZvcmhyLmNvbS9pbmRleC5odG1sI2hyYWdyb3d0aCANCi0gQ3JhbmZvcmQsIEouIEEuLCBTaHJvdXQsIFAuIEUuLCBJaWRhLCBNLiwgUmFmYWVsaSwgRS4sIFlpcCwgVC4sICYgQm9sZ2VyLCBOLiAoMjAwNikuIEEgUHJvY2VkdXJlIGZvciBFdmFsdWF0aW5nIFNlbnNpdGl2aXR5IHRvIFdpdGhpbi1QZXJzb24gQ2hhbmdlOiBDYW4gTW9vZCBNZWFzdXJlcyBpbiBEaWFyeSBTdHVkaWVzIERldGVjdCBDaGFuZ2UgUmVsaWFibHk/ICpQZXJzb25hbGl0eSBhbmQgU29jaWFsIFBzeWNob2xvZ3kgQnVsbGV0aW4sIDMyKig3KSwgOTE3LS05MjkuIDxodHRwczovL2RvaS5vcmcvMTAuMTE3Ny8wMTQ2MTY3MjA2Mjg3NzIxPg0KDQotIEN1cnJhbiwgUC4gRy4gKDIwMTYpLiBNZXRob2RzIGZvciB0aGUgZGV0ZWN0aW9uIG9mIGNhcmVsZXNzbHkgaW52YWxpZCByZXNwb25zZXMgaW4gc3VydmV5IGRhdGEuIEpvdXJuYWwgb2YgRXhwZXJpbWVudGFsIFNvY2lhbCBQc3ljaG9sb2d5LCA2NiwgNC0xOS4gPGh0dHBzOi8vZG9pLm9yZy8xMC4xMDE2L2ouamVzcC4yMDE1LjA3LjAwNj4NCg0KLSBFaW5zcHJ1Y2gsIEUuIEwuICgyMDIyKS4gKkFuIEludHJvZHVjdG9yeSBHdWlkZSB0byBSOiBFYXNpbmcgdGhlIExlYXJuaW5nIEN1cnZlKi4gR3VpbGZvcmQgUHJlc3MuDQoNCi0gR2VsZGhvZiwgRy4gSi4sIFByZWFjaGVyLCBLLiBKLiwgJiBaeXBodXIsIE0uIEouICgyMDE0KS4gUmVsaWFiaWxpdHkgZXN0aW1hdGlvbiBpbiBhIG11bHRpbGV2ZWwgY29uZmlybWF0b3J5IGZhY3RvciBhbmFseXNpcyBmcmFtZXdvcmsuICpQc3ljaG9sb2dpY2FsIE1ldGhvZHMsIDE5KigxKSwgNzLigJM5MS4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwMzcvYTAwMzIxMzgNCg0KLSBXaWNraGFtLCBILiwgQ2V0aW5rYXlhLVJ1bmRlbCwgTS4sICYgR3JvbGVtdW5kICBHLiAoMjAyMykuIFIgZm9yIERhdGEgU2NpZW5jZTogSW1wb3J0LCBUaWR5LCBUcmFuc2Zvcm0sIFZpc3VhbGl6ZSwgYW5kIE1vZGVsICgybmQgRWQuKS4gT+KAmVJlaWxseS4gQXZhaWxhYmxlIGF0IGh0dHBzOi8vcjRkcy5oYWRsZXkubnovDQoNCi0gSGFtYWtlciwgRS4gTC4sICYgR3Jhc21hbiwgUi4gUC4gUC4gUC4gKDIwMTUpLiBUbyBjZW50ZXIgb3Igbm90IHRvIGNlbnRlcj8gSW52ZXN0aWdhdGluZyBpbmVydGlhIHdpdGggYSBtdWx0aWxldmVsIGF1dG9yZWdyZXNzaXZlIG1vZGVsLiBGcm9udGllcnMgaW4gUHN5Y2hvbG9neSwgNS4gaHR0cHM6Ly9kb2kub3JnLzEwLjMzODkvZnBzeWcuMjAxNC4wMTQ5MiANCg0KLSBIdWFuZywgSi4gTC4sIEN1cnJhbiwgUC4gRy4sIEtlZW5leSwgSi4sIFBvcG9za2ksIEUuIE0uLCAmIERlU2hvbiwgUi4gUC4gKDIwMTIpLiBEZXRlY3RpbmcgYW5kIGRldGVycmluZyBpbnN1ZmZpY2llbnQgZWZmb3J0IHJlc3BvbmRpbmcgdG8gc3VydmV5cy4gSm91cm5hbCBvZiBCdXNpbmVzcyBhbmQgUHN5Y2hvbG9neSwgMjcsIDk5LTExNC4gPGh0dHBzOi8vZG9pLm9yZy8xMC4xMDA3L3MxMDg2OS0wMTEtOTIzMS04Pg0KDQotIEphaywgUy4sICYgSm9yZ2Vuc2VuLCBULiBELiAoMjAxNykuIFJlbGF0aW5nIG1lYXN1cmVtZW50IGludmFyaWFuY2UsIGNyb3NzLWxldmVsIGludmFyaWFuY2UsIGFuZCBtdWx0aWxldmVsIHJlbGlhYmlsaXR5LiAqRnJvbnRpZXJzIGluIHBzeWNob2xvZ3ksIDgqLCAxNjQwLiA8aHR0cHM6Ly9kb2kub3JnLzEwLjMzODkvZnBzeWcuMjAxNy4wMTY0MD4NCg0KLSBLYWJhY29mZiwgUi4gSS4gKDIwMjIpLiAqUiBpbiBBY3Rpb246IERhdGEgYW5hbHlzaXMgYW5kIGdyYXBoaWNzIHdpdGggUiBhbmQgVGlkeXZlcnNlKiAoM3JkLiBFZCkuIE1hbm5pbmcuDQoNCi0gS2FyYXNlaywgUi4gQS4gKDE5NzkpLiBKb2IgRGVtYW5kcywgSm9iIERlY2lzaW9uIExhdGl0dWRlLCBhbmQgTWVudGFsIFN0cmFpbjogSW1wbGljYXRpb25zIGZvciBKb2IgUmVkZXNpZ24uICpBZG1pbmlzdHJhdGl2ZSBTY2llbmNlIFF1YXJ0ZXJseSwgMjQqKDIpLCAyODUtLTMwOC4gPGh0dHBzOi8vZG9pLm9yZy8xMC4yMzA3LzIzOTI0OTg+DQoNCi0gTWNOZWlzaCwgRC4gKDIwMTcpLiBTbWFsbCBTYW1wbGUgTWV0aG9kcyBmb3IgTXVsdGlsZXZlbCBNb2RlbGluZzogQSBDb2xsb3F1aWFsIEVsdWNpZGF0aW9uIG9mIFJFTUwgYW5kIHRoZSBLZW53YXJkLVJvZ2VyIENvcnJlY3Rpb24uICpNdWx0aXZhcmlhdGUgQmVoYXZpb3JhbCBSZXNlYXJjaCwgNTIqKDUpLCA2NjHigJM2NzAuIGh0dHBzOi8vZG9pLm9yZy8xMC4xMDgwLzAwMjczMTcxLjIwMTcuMTM0NDUzOA0KDQotIE1jTnVsdHksIEsuICgyMDIyKS4gKkhhbmRib29rIG9mIFJlZ3Jlc3Npb24gTW9kZWxpbmcgaW4gUGVvcGxlIEFuYWx5dGljczogV2l0aCBFeGFtcGxlcyBpbiBSLCBQeXRob24gYW5kIEp1bGlhKi4gQ1JDIFByZXNzLiBGcmVlbHkgYXZhaWxhYmxlIGF0IGh0dHBzOi8vcGVvcGxlYW5hbHl0aWNzLXJlZ3Jlc3Npb24tYm9vay5vcmcvaW5kZXguaHRtbA0KDQotIE1lbmdoaW5pLCBMLiwgUGFzdG9yZSwgTS4sICYgQmFsZHVjY2ksIEMuICgyMDIzKS4gV29ya3BsYWNlIFN0cmVzcyBpbiBSZWFsIFRpbWU6IFRocmVlIFBhcnNpbW9uaW91cyBTY2FsZXMgZm9yIHRoZSBFeHBlcmllbmNlIFNhbXBsaW5nIE1lYXN1cmVtZW50IG9mIFN0cmVzc29ycyBhbmQgU3RyYWluIGF0IFdvcmsuICpFdXJvcGVhbiBKb3VybmFsIG9mIFBzeWNob2xvZ2ljYWwgQXNzZXNzbWVudCwgMzkqKDYpLCA0MjTigJM0MzIuIGh0dHBzOi8vZG9pLm9yZy8xMC4xMDI3LzEwMTUtNTc1OS9hMDAwNzI1DQoNCi0gU2hyb3V0LCBQLiBFLiwgJiBMYW5lLCBTLiBQLiAoMjAxMikuIFBzeWNob21ldHJpY3MuIEluIE0uIFIuIE1laGwgJiBULiBTLiBDb25uZXIgKEVkcy4pLCAqSGFuZGJvb2sgb2YgcmVzZWFyY2ggbWV0aG9kcyBmb3Igc3R1ZHlpbmcgZGFpbHkgbGlmZSogKHBwLiAzMDItLTMyMCkuIFRoZSBHdWlsZm9yZCBQcmVzcy4NCg0KLSBTdGFyYnVjaywgQy4gKDIwMjMpLiAqVGhlIEZ1bmRhbWVudGFscyBvZiBQZW9wbGUgQW5hbHl0aWNzIFdpdGggQXBwbGljYXRpb25zIGluIFIqLiBTcHJpbmdlci4gRnJlZWx5IGF2YWlsYWJsZSBhdCBodHRwczovL2xpbmsuc3ByaW5nZXIuY29tL2Jvb2svMTAuMTAwNy85NzgtMy0wMzEtMjg2NzQtMiANCg0KLSBXYW5nLCBMLiBQLiwgJiBNYXh3ZWxsLCBTLiBFLiAoMjAxNSkuIE9uIGRpc2FnZ3JlZ2F0aW5nIGJldHdlZW4tcGVyc29uIGFuZCB3aXRoaW4tcGVyc29uIGVmZmVjdHMgd2l0aCBsb25naXR1ZGluYWwgZGF0YSB1c2luZyBtdWx0aWxldmVsIG1vZGVscy4gKlBzeWNob2xvZ2ljYWwgTWV0aG9kcywgMjAqKDEpLCA2M+KAkzgzLiBodHRwczovL2RvaS5vcmcvMTAuMTAzNy9tZXQwMDAwMDMwIA0KDQotIFdpY2toYW0sIEguLCDDh2V0aW5rYXlhLVJ1bmRlbCwgTS4sICYgR3JvbGVtdW5kLCBHLiAoMjAyMykuICpSIGZvciBEYXRhIFNjaWVuY2U6IEltcG9ydCwgVGlkeSwgVHJhbnNmb3JtLCBWaXN1YWxpemUsIGFuZCBNb2RlbCBEYXRhKiAoMm5kIEVkLikuIE8nUmVpbGx5Lg0KDQo8YnI+DQoNCiMjIFIgcGFja2FnZXMNCg==